1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2013 Samsung Electronics Co., Ltd.
4*4882a593Smuzhiyun * Copyright (c) 2013 Linaro Ltd.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This file contains the utility functions to register the pll clocks.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/hrtimer.h>
11*4882a593Smuzhiyun #include <linux/delay.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/clk-provider.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include "clk.h"
16*4882a593Smuzhiyun #include "clk-pll.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define PLL_TIMEOUT_MS 10
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun struct samsung_clk_pll {
21*4882a593Smuzhiyun struct clk_hw hw;
22*4882a593Smuzhiyun void __iomem *lock_reg;
23*4882a593Smuzhiyun void __iomem *con_reg;
24*4882a593Smuzhiyun /* PLL enable control bit offset in @con_reg register */
25*4882a593Smuzhiyun unsigned short enable_offs;
26*4882a593Smuzhiyun /* PLL lock status bit offset in @con_reg register */
27*4882a593Smuzhiyun unsigned short lock_offs;
28*4882a593Smuzhiyun enum samsung_pll_type type;
29*4882a593Smuzhiyun unsigned int rate_count;
30*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate_table;
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
34*4882a593Smuzhiyun
samsung_get_pll_settings(struct samsung_clk_pll * pll,unsigned long rate)35*4882a593Smuzhiyun static const struct samsung_pll_rate_table *samsung_get_pll_settings(
36*4882a593Smuzhiyun struct samsung_clk_pll *pll, unsigned long rate)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate_table = pll->rate_table;
39*4882a593Smuzhiyun int i;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun for (i = 0; i < pll->rate_count; i++) {
42*4882a593Smuzhiyun if (rate == rate_table[i].rate)
43*4882a593Smuzhiyun return &rate_table[i];
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return NULL;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
samsung_pll_round_rate(struct clk_hw * hw,unsigned long drate,unsigned long * prate)49*4882a593Smuzhiyun static long samsung_pll_round_rate(struct clk_hw *hw,
50*4882a593Smuzhiyun unsigned long drate, unsigned long *prate)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
53*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate_table = pll->rate_table;
54*4882a593Smuzhiyun int i;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* Assumming rate_table is in descending order */
57*4882a593Smuzhiyun for (i = 0; i < pll->rate_count; i++) {
58*4882a593Smuzhiyun if (drate >= rate_table[i].rate)
59*4882a593Smuzhiyun return rate_table[i].rate;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* return minimum supported value */
63*4882a593Smuzhiyun return rate_table[i - 1].rate;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
samsung_pll3xxx_enable(struct clk_hw * hw)66*4882a593Smuzhiyun static int samsung_pll3xxx_enable(struct clk_hw *hw)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
69*4882a593Smuzhiyun u32 tmp;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
72*4882a593Smuzhiyun tmp |= BIT(pll->enable_offs);
73*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* wait lock time */
76*4882a593Smuzhiyun do {
77*4882a593Smuzhiyun cpu_relax();
78*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
79*4882a593Smuzhiyun } while (!(tmp & BIT(pll->lock_offs)));
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return 0;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
samsung_pll3xxx_disable(struct clk_hw * hw)84*4882a593Smuzhiyun static void samsung_pll3xxx_disable(struct clk_hw *hw)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
87*4882a593Smuzhiyun u32 tmp;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
90*4882a593Smuzhiyun tmp &= ~BIT(pll->enable_offs);
91*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * PLL2126 Clock Type
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun #define PLL2126_MDIV_MASK (0xff)
99*4882a593Smuzhiyun #define PLL2126_PDIV_MASK (0x3f)
100*4882a593Smuzhiyun #define PLL2126_SDIV_MASK (0x3)
101*4882a593Smuzhiyun #define PLL2126_MDIV_SHIFT (16)
102*4882a593Smuzhiyun #define PLL2126_PDIV_SHIFT (8)
103*4882a593Smuzhiyun #define PLL2126_SDIV_SHIFT (0)
104*4882a593Smuzhiyun
samsung_pll2126_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)105*4882a593Smuzhiyun static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
106*4882a593Smuzhiyun unsigned long parent_rate)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
109*4882a593Smuzhiyun u32 pll_con, mdiv, pdiv, sdiv;
110*4882a593Smuzhiyun u64 fvco = parent_rate;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
113*4882a593Smuzhiyun mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
114*4882a593Smuzhiyun pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
115*4882a593Smuzhiyun sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun fvco *= (mdiv + 8);
118*4882a593Smuzhiyun do_div(fvco, (pdiv + 2) << sdiv);
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return (unsigned long)fvco;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun static const struct clk_ops samsung_pll2126_clk_ops = {
124*4882a593Smuzhiyun .recalc_rate = samsung_pll2126_recalc_rate,
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun * PLL3000 Clock Type
129*4882a593Smuzhiyun */
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun #define PLL3000_MDIV_MASK (0xff)
132*4882a593Smuzhiyun #define PLL3000_PDIV_MASK (0x3)
133*4882a593Smuzhiyun #define PLL3000_SDIV_MASK (0x3)
134*4882a593Smuzhiyun #define PLL3000_MDIV_SHIFT (16)
135*4882a593Smuzhiyun #define PLL3000_PDIV_SHIFT (8)
136*4882a593Smuzhiyun #define PLL3000_SDIV_SHIFT (0)
137*4882a593Smuzhiyun
samsung_pll3000_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)138*4882a593Smuzhiyun static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
139*4882a593Smuzhiyun unsigned long parent_rate)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
142*4882a593Smuzhiyun u32 pll_con, mdiv, pdiv, sdiv;
143*4882a593Smuzhiyun u64 fvco = parent_rate;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
146*4882a593Smuzhiyun mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
147*4882a593Smuzhiyun pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
148*4882a593Smuzhiyun sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun fvco *= (2 * (mdiv + 8));
151*4882a593Smuzhiyun do_div(fvco, pdiv << sdiv);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun return (unsigned long)fvco;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun static const struct clk_ops samsung_pll3000_clk_ops = {
157*4882a593Smuzhiyun .recalc_rate = samsung_pll3000_recalc_rate,
158*4882a593Smuzhiyun };
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun * PLL35xx Clock Type
162*4882a593Smuzhiyun */
163*4882a593Smuzhiyun /* Maximum lock time can be 270 * PDIV cycles */
164*4882a593Smuzhiyun #define PLL35XX_LOCK_FACTOR (270)
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun #define PLL35XX_MDIV_MASK (0x3FF)
167*4882a593Smuzhiyun #define PLL35XX_PDIV_MASK (0x3F)
168*4882a593Smuzhiyun #define PLL35XX_SDIV_MASK (0x7)
169*4882a593Smuzhiyun #define PLL35XX_MDIV_SHIFT (16)
170*4882a593Smuzhiyun #define PLL35XX_PDIV_SHIFT (8)
171*4882a593Smuzhiyun #define PLL35XX_SDIV_SHIFT (0)
172*4882a593Smuzhiyun #define PLL35XX_LOCK_STAT_SHIFT (29)
173*4882a593Smuzhiyun #define PLL35XX_ENABLE_SHIFT (31)
174*4882a593Smuzhiyun
samsung_pll35xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)175*4882a593Smuzhiyun static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
176*4882a593Smuzhiyun unsigned long parent_rate)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
179*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con;
180*4882a593Smuzhiyun u64 fvco = parent_rate;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
183*4882a593Smuzhiyun mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
184*4882a593Smuzhiyun pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
185*4882a593Smuzhiyun sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun fvco *= mdiv;
188*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun return (unsigned long)fvco;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
samsung_pll35xx_mp_change(const struct samsung_pll_rate_table * rate,u32 pll_con)193*4882a593Smuzhiyun static inline bool samsung_pll35xx_mp_change(
194*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate, u32 pll_con)
195*4882a593Smuzhiyun {
196*4882a593Smuzhiyun u32 old_mdiv, old_pdiv;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
199*4882a593Smuzhiyun old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
samsung_pll35xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)204*4882a593Smuzhiyun static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
205*4882a593Smuzhiyun unsigned long prate)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
208*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
209*4882a593Smuzhiyun u32 tmp;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* Get required rate settings from table */
212*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
213*4882a593Smuzhiyun if (!rate) {
214*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
215*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
216*4882a593Smuzhiyun return -EINVAL;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (!(samsung_pll35xx_mp_change(rate, tmp))) {
222*4882a593Smuzhiyun /* If only s change, change just s value only*/
223*4882a593Smuzhiyun tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
224*4882a593Smuzhiyun tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
225*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun return 0;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun /* Set PLL lock time. */
231*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL35XX_LOCK_FACTOR,
232*4882a593Smuzhiyun pll->lock_reg);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun /* Change PLL PMS values */
235*4882a593Smuzhiyun tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
236*4882a593Smuzhiyun (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
237*4882a593Smuzhiyun (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
238*4882a593Smuzhiyun tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
239*4882a593Smuzhiyun (rate->pdiv << PLL35XX_PDIV_SHIFT) |
240*4882a593Smuzhiyun (rate->sdiv << PLL35XX_SDIV_SHIFT);
241*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* Wait until the PLL is locked if it is enabled. */
244*4882a593Smuzhiyun if (tmp & BIT(pll->enable_offs)) {
245*4882a593Smuzhiyun do {
246*4882a593Smuzhiyun cpu_relax();
247*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
248*4882a593Smuzhiyun } while (!(tmp & BIT(pll->lock_offs)));
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun return 0;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun static const struct clk_ops samsung_pll35xx_clk_ops = {
254*4882a593Smuzhiyun .recalc_rate = samsung_pll35xx_recalc_rate,
255*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
256*4882a593Smuzhiyun .set_rate = samsung_pll35xx_set_rate,
257*4882a593Smuzhiyun .enable = samsung_pll3xxx_enable,
258*4882a593Smuzhiyun .disable = samsung_pll3xxx_disable,
259*4882a593Smuzhiyun };
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun static const struct clk_ops samsung_pll35xx_clk_min_ops = {
262*4882a593Smuzhiyun .recalc_rate = samsung_pll35xx_recalc_rate,
263*4882a593Smuzhiyun };
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /*
266*4882a593Smuzhiyun * PLL36xx Clock Type
267*4882a593Smuzhiyun */
268*4882a593Smuzhiyun /* Maximum lock time can be 3000 * PDIV cycles */
269*4882a593Smuzhiyun #define PLL36XX_LOCK_FACTOR (3000)
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun #define PLL36XX_KDIV_MASK (0xFFFF)
272*4882a593Smuzhiyun #define PLL36XX_MDIV_MASK (0x1FF)
273*4882a593Smuzhiyun #define PLL36XX_PDIV_MASK (0x3F)
274*4882a593Smuzhiyun #define PLL36XX_SDIV_MASK (0x7)
275*4882a593Smuzhiyun #define PLL36XX_MDIV_SHIFT (16)
276*4882a593Smuzhiyun #define PLL36XX_PDIV_SHIFT (8)
277*4882a593Smuzhiyun #define PLL36XX_SDIV_SHIFT (0)
278*4882a593Smuzhiyun #define PLL36XX_KDIV_SHIFT (0)
279*4882a593Smuzhiyun #define PLL36XX_LOCK_STAT_SHIFT (29)
280*4882a593Smuzhiyun #define PLL36XX_ENABLE_SHIFT (31)
281*4882a593Smuzhiyun
samsung_pll36xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)282*4882a593Smuzhiyun static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
283*4882a593Smuzhiyun unsigned long parent_rate)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
286*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
287*4882a593Smuzhiyun s16 kdiv;
288*4882a593Smuzhiyun u64 fvco = parent_rate;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
291*4882a593Smuzhiyun pll_con1 = readl_relaxed(pll->con_reg + 4);
292*4882a593Smuzhiyun mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
293*4882a593Smuzhiyun pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
294*4882a593Smuzhiyun sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
295*4882a593Smuzhiyun kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun fvco *= (mdiv << 16) + kdiv;
298*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
299*4882a593Smuzhiyun fvco >>= 16;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun return (unsigned long)fvco;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
samsung_pll36xx_mpk_change(const struct samsung_pll_rate_table * rate,u32 pll_con0,u32 pll_con1)304*4882a593Smuzhiyun static inline bool samsung_pll36xx_mpk_change(
305*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun u32 old_mdiv, old_pdiv, old_kdiv;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
310*4882a593Smuzhiyun old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
311*4882a593Smuzhiyun old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
314*4882a593Smuzhiyun rate->kdiv != old_kdiv);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
samsung_pll36xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long parent_rate)317*4882a593Smuzhiyun static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
318*4882a593Smuzhiyun unsigned long parent_rate)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
321*4882a593Smuzhiyun u32 tmp, pll_con0, pll_con1;
322*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
325*4882a593Smuzhiyun if (!rate) {
326*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
327*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
328*4882a593Smuzhiyun return -EINVAL;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
332*4882a593Smuzhiyun pll_con1 = readl_relaxed(pll->con_reg + 4);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
335*4882a593Smuzhiyun /* If only s change, change just s value only*/
336*4882a593Smuzhiyun pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
337*4882a593Smuzhiyun pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
338*4882a593Smuzhiyun writel_relaxed(pll_con0, pll->con_reg);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun return 0;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun /* Set PLL lock time. */
344*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* Change PLL PMS values */
347*4882a593Smuzhiyun pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
348*4882a593Smuzhiyun (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
349*4882a593Smuzhiyun (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
350*4882a593Smuzhiyun pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
351*4882a593Smuzhiyun (rate->pdiv << PLL36XX_PDIV_SHIFT) |
352*4882a593Smuzhiyun (rate->sdiv << PLL36XX_SDIV_SHIFT);
353*4882a593Smuzhiyun writel_relaxed(pll_con0, pll->con_reg);
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
356*4882a593Smuzhiyun pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
357*4882a593Smuzhiyun writel_relaxed(pll_con1, pll->con_reg + 4);
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /* wait_lock_time */
360*4882a593Smuzhiyun if (pll_con0 & BIT(pll->enable_offs)) {
361*4882a593Smuzhiyun do {
362*4882a593Smuzhiyun cpu_relax();
363*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
364*4882a593Smuzhiyun } while (!(tmp & BIT(pll->lock_offs)));
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun static const struct clk_ops samsung_pll36xx_clk_ops = {
371*4882a593Smuzhiyun .recalc_rate = samsung_pll36xx_recalc_rate,
372*4882a593Smuzhiyun .set_rate = samsung_pll36xx_set_rate,
373*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
374*4882a593Smuzhiyun .enable = samsung_pll3xxx_enable,
375*4882a593Smuzhiyun .disable = samsung_pll3xxx_disable,
376*4882a593Smuzhiyun };
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun static const struct clk_ops samsung_pll36xx_clk_min_ops = {
379*4882a593Smuzhiyun .recalc_rate = samsung_pll36xx_recalc_rate,
380*4882a593Smuzhiyun };
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun * PLL45xx Clock Type
384*4882a593Smuzhiyun */
385*4882a593Smuzhiyun #define PLL4502_LOCK_FACTOR 400
386*4882a593Smuzhiyun #define PLL4508_LOCK_FACTOR 240
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun #define PLL45XX_MDIV_MASK (0x3FF)
389*4882a593Smuzhiyun #define PLL45XX_PDIV_MASK (0x3F)
390*4882a593Smuzhiyun #define PLL45XX_SDIV_MASK (0x7)
391*4882a593Smuzhiyun #define PLL45XX_AFC_MASK (0x1F)
392*4882a593Smuzhiyun #define PLL45XX_MDIV_SHIFT (16)
393*4882a593Smuzhiyun #define PLL45XX_PDIV_SHIFT (8)
394*4882a593Smuzhiyun #define PLL45XX_SDIV_SHIFT (0)
395*4882a593Smuzhiyun #define PLL45XX_AFC_SHIFT (0)
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun #define PLL45XX_ENABLE BIT(31)
398*4882a593Smuzhiyun #define PLL45XX_LOCKED BIT(29)
399*4882a593Smuzhiyun
samsung_pll45xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)400*4882a593Smuzhiyun static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
401*4882a593Smuzhiyun unsigned long parent_rate)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
404*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con;
405*4882a593Smuzhiyun u64 fvco = parent_rate;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
408*4882a593Smuzhiyun mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
409*4882a593Smuzhiyun pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
410*4882a593Smuzhiyun sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun if (pll->type == pll_4508)
413*4882a593Smuzhiyun sdiv = sdiv - 1;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun fvco *= mdiv;
416*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun return (unsigned long)fvco;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
samsung_pll45xx_mp_change(u32 pll_con0,u32 pll_con1,const struct samsung_pll_rate_table * rate)421*4882a593Smuzhiyun static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
422*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun u32 old_mdiv, old_pdiv, old_afc;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
427*4882a593Smuzhiyun old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
428*4882a593Smuzhiyun old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
431*4882a593Smuzhiyun || old_afc != rate->afc);
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
samsung_pll45xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)434*4882a593Smuzhiyun static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
435*4882a593Smuzhiyun unsigned long prate)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
438*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
439*4882a593Smuzhiyun u32 con0, con1;
440*4882a593Smuzhiyun ktime_t start;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun /* Get required rate settings from table */
443*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
444*4882a593Smuzhiyun if (!rate) {
445*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
446*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
447*4882a593Smuzhiyun return -EINVAL;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun con0 = readl_relaxed(pll->con_reg);
451*4882a593Smuzhiyun con1 = readl_relaxed(pll->con_reg + 0x4);
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun if (!(samsung_pll45xx_mp_change(con0, con1, rate))) {
454*4882a593Smuzhiyun /* If only s change, change just s value only*/
455*4882a593Smuzhiyun con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT);
456*4882a593Smuzhiyun con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT;
457*4882a593Smuzhiyun writel_relaxed(con0, pll->con_reg);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun return 0;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /* Set PLL PMS values. */
463*4882a593Smuzhiyun con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) |
464*4882a593Smuzhiyun (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) |
465*4882a593Smuzhiyun (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT));
466*4882a593Smuzhiyun con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) |
467*4882a593Smuzhiyun (rate->pdiv << PLL45XX_PDIV_SHIFT) |
468*4882a593Smuzhiyun (rate->sdiv << PLL45XX_SDIV_SHIFT);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun /* Set PLL AFC value. */
471*4882a593Smuzhiyun con1 = readl_relaxed(pll->con_reg + 0x4);
472*4882a593Smuzhiyun con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT);
473*4882a593Smuzhiyun con1 |= (rate->afc << PLL45XX_AFC_SHIFT);
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* Set PLL lock time. */
476*4882a593Smuzhiyun switch (pll->type) {
477*4882a593Smuzhiyun case pll_4502:
478*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg);
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun case pll_4508:
481*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg);
482*4882a593Smuzhiyun break;
483*4882a593Smuzhiyun default:
484*4882a593Smuzhiyun break;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun /* Set new configuration. */
488*4882a593Smuzhiyun writel_relaxed(con1, pll->con_reg + 0x4);
489*4882a593Smuzhiyun writel_relaxed(con0, pll->con_reg);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun /* Wait for locking. */
492*4882a593Smuzhiyun start = ktime_get();
493*4882a593Smuzhiyun while (!(readl_relaxed(pll->con_reg) & PLL45XX_LOCKED)) {
494*4882a593Smuzhiyun ktime_t delta = ktime_sub(ktime_get(), start);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
497*4882a593Smuzhiyun pr_err("%s: could not lock PLL %s\n",
498*4882a593Smuzhiyun __func__, clk_hw_get_name(hw));
499*4882a593Smuzhiyun return -EFAULT;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun cpu_relax();
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun return 0;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun static const struct clk_ops samsung_pll45xx_clk_ops = {
509*4882a593Smuzhiyun .recalc_rate = samsung_pll45xx_recalc_rate,
510*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
511*4882a593Smuzhiyun .set_rate = samsung_pll45xx_set_rate,
512*4882a593Smuzhiyun };
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun static const struct clk_ops samsung_pll45xx_clk_min_ops = {
515*4882a593Smuzhiyun .recalc_rate = samsung_pll45xx_recalc_rate,
516*4882a593Smuzhiyun };
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * PLL46xx Clock Type
520*4882a593Smuzhiyun */
521*4882a593Smuzhiyun #define PLL46XX_LOCK_FACTOR 3000
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun #define PLL46XX_VSEL_MASK (1)
524*4882a593Smuzhiyun #define PLL46XX_MDIV_MASK (0x1FF)
525*4882a593Smuzhiyun #define PLL1460X_MDIV_MASK (0x3FF)
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun #define PLL46XX_PDIV_MASK (0x3F)
528*4882a593Smuzhiyun #define PLL46XX_SDIV_MASK (0x7)
529*4882a593Smuzhiyun #define PLL46XX_VSEL_SHIFT (27)
530*4882a593Smuzhiyun #define PLL46XX_MDIV_SHIFT (16)
531*4882a593Smuzhiyun #define PLL46XX_PDIV_SHIFT (8)
532*4882a593Smuzhiyun #define PLL46XX_SDIV_SHIFT (0)
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun #define PLL46XX_KDIV_MASK (0xFFFF)
535*4882a593Smuzhiyun #define PLL4650C_KDIV_MASK (0xFFF)
536*4882a593Smuzhiyun #define PLL46XX_KDIV_SHIFT (0)
537*4882a593Smuzhiyun #define PLL46XX_MFR_MASK (0x3F)
538*4882a593Smuzhiyun #define PLL46XX_MRR_MASK (0x1F)
539*4882a593Smuzhiyun #define PLL46XX_KDIV_SHIFT (0)
540*4882a593Smuzhiyun #define PLL46XX_MFR_SHIFT (16)
541*4882a593Smuzhiyun #define PLL46XX_MRR_SHIFT (24)
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun #define PLL46XX_ENABLE BIT(31)
544*4882a593Smuzhiyun #define PLL46XX_LOCKED BIT(29)
545*4882a593Smuzhiyun #define PLL46XX_VSEL BIT(27)
546*4882a593Smuzhiyun
samsung_pll46xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)547*4882a593Smuzhiyun static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
548*4882a593Smuzhiyun unsigned long parent_rate)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
551*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
552*4882a593Smuzhiyun u64 fvco = parent_rate;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
555*4882a593Smuzhiyun pll_con1 = readl_relaxed(pll->con_reg + 4);
556*4882a593Smuzhiyun mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & ((pll->type == pll_1460x) ?
557*4882a593Smuzhiyun PLL1460X_MDIV_MASK : PLL46XX_MDIV_MASK);
558*4882a593Smuzhiyun pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
559*4882a593Smuzhiyun sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
560*4882a593Smuzhiyun kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
561*4882a593Smuzhiyun pll_con1 & PLL46XX_KDIV_MASK;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun shift = ((pll->type == pll_4600) || (pll->type == pll_1460x)) ? 16 : 10;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun fvco *= (mdiv << shift) + kdiv;
566*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
567*4882a593Smuzhiyun fvco >>= shift;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun return (unsigned long)fvco;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
samsung_pll46xx_mpk_change(u32 pll_con0,u32 pll_con1,const struct samsung_pll_rate_table * rate)572*4882a593Smuzhiyun static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
573*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun u32 old_mdiv, old_pdiv, old_kdiv;
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
578*4882a593Smuzhiyun old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
579*4882a593Smuzhiyun old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
582*4882a593Smuzhiyun || old_kdiv != rate->kdiv);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun
samsung_pll46xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)585*4882a593Smuzhiyun static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
586*4882a593Smuzhiyun unsigned long prate)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
589*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
590*4882a593Smuzhiyun u32 con0, con1, lock;
591*4882a593Smuzhiyun ktime_t start;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun /* Get required rate settings from table */
594*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
595*4882a593Smuzhiyun if (!rate) {
596*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
597*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
598*4882a593Smuzhiyun return -EINVAL;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun con0 = readl_relaxed(pll->con_reg);
602*4882a593Smuzhiyun con1 = readl_relaxed(pll->con_reg + 0x4);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
605*4882a593Smuzhiyun /* If only s change, change just s value only*/
606*4882a593Smuzhiyun con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
607*4882a593Smuzhiyun con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
608*4882a593Smuzhiyun writel_relaxed(con0, pll->con_reg);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun return 0;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /* Set PLL lock time. */
614*4882a593Smuzhiyun lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
615*4882a593Smuzhiyun if (lock > 0xffff)
616*4882a593Smuzhiyun /* Maximum lock time bitfield is 16-bit. */
617*4882a593Smuzhiyun lock = 0xffff;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun /* Set PLL PMS and VSEL values. */
620*4882a593Smuzhiyun if (pll->type == pll_1460x) {
621*4882a593Smuzhiyun con0 &= ~((PLL1460X_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
622*4882a593Smuzhiyun (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
623*4882a593Smuzhiyun (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT));
624*4882a593Smuzhiyun } else {
625*4882a593Smuzhiyun con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
626*4882a593Smuzhiyun (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
627*4882a593Smuzhiyun (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
628*4882a593Smuzhiyun (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
629*4882a593Smuzhiyun con0 |= rate->vsel << PLL46XX_VSEL_SHIFT;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
633*4882a593Smuzhiyun (rate->pdiv << PLL46XX_PDIV_SHIFT) |
634*4882a593Smuzhiyun (rate->sdiv << PLL46XX_SDIV_SHIFT);
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun /* Set PLL K, MFR and MRR values. */
637*4882a593Smuzhiyun con1 = readl_relaxed(pll->con_reg + 0x4);
638*4882a593Smuzhiyun con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
639*4882a593Smuzhiyun (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
640*4882a593Smuzhiyun (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
641*4882a593Smuzhiyun con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
642*4882a593Smuzhiyun (rate->mfr << PLL46XX_MFR_SHIFT) |
643*4882a593Smuzhiyun (rate->mrr << PLL46XX_MRR_SHIFT);
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /* Write configuration to PLL */
646*4882a593Smuzhiyun writel_relaxed(lock, pll->lock_reg);
647*4882a593Smuzhiyun writel_relaxed(con0, pll->con_reg);
648*4882a593Smuzhiyun writel_relaxed(con1, pll->con_reg + 0x4);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun /* Wait for locking. */
651*4882a593Smuzhiyun start = ktime_get();
652*4882a593Smuzhiyun while (!(readl_relaxed(pll->con_reg) & PLL46XX_LOCKED)) {
653*4882a593Smuzhiyun ktime_t delta = ktime_sub(ktime_get(), start);
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
656*4882a593Smuzhiyun pr_err("%s: could not lock PLL %s\n",
657*4882a593Smuzhiyun __func__, clk_hw_get_name(hw));
658*4882a593Smuzhiyun return -EFAULT;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun cpu_relax();
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun return 0;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun static const struct clk_ops samsung_pll46xx_clk_ops = {
668*4882a593Smuzhiyun .recalc_rate = samsung_pll46xx_recalc_rate,
669*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
670*4882a593Smuzhiyun .set_rate = samsung_pll46xx_set_rate,
671*4882a593Smuzhiyun };
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun static const struct clk_ops samsung_pll46xx_clk_min_ops = {
674*4882a593Smuzhiyun .recalc_rate = samsung_pll46xx_recalc_rate,
675*4882a593Smuzhiyun };
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /*
678*4882a593Smuzhiyun * PLL6552 Clock Type
679*4882a593Smuzhiyun */
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun #define PLL6552_MDIV_MASK 0x3ff
682*4882a593Smuzhiyun #define PLL6552_PDIV_MASK 0x3f
683*4882a593Smuzhiyun #define PLL6552_SDIV_MASK 0x7
684*4882a593Smuzhiyun #define PLL6552_MDIV_SHIFT 16
685*4882a593Smuzhiyun #define PLL6552_MDIV_SHIFT_2416 14
686*4882a593Smuzhiyun #define PLL6552_PDIV_SHIFT 8
687*4882a593Smuzhiyun #define PLL6552_PDIV_SHIFT_2416 5
688*4882a593Smuzhiyun #define PLL6552_SDIV_SHIFT 0
689*4882a593Smuzhiyun
samsung_pll6552_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)690*4882a593Smuzhiyun static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
691*4882a593Smuzhiyun unsigned long parent_rate)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
694*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con;
695*4882a593Smuzhiyun u64 fvco = parent_rate;
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
698*4882a593Smuzhiyun if (pll->type == pll_6552_s3c2416) {
699*4882a593Smuzhiyun mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
700*4882a593Smuzhiyun pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
701*4882a593Smuzhiyun } else {
702*4882a593Smuzhiyun mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
703*4882a593Smuzhiyun pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun fvco *= mdiv;
708*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun return (unsigned long)fvco;
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun static const struct clk_ops samsung_pll6552_clk_ops = {
714*4882a593Smuzhiyun .recalc_rate = samsung_pll6552_recalc_rate,
715*4882a593Smuzhiyun };
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /*
718*4882a593Smuzhiyun * PLL6553 Clock Type
719*4882a593Smuzhiyun */
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun #define PLL6553_MDIV_MASK 0xff
722*4882a593Smuzhiyun #define PLL6553_PDIV_MASK 0x3f
723*4882a593Smuzhiyun #define PLL6553_SDIV_MASK 0x7
724*4882a593Smuzhiyun #define PLL6553_KDIV_MASK 0xffff
725*4882a593Smuzhiyun #define PLL6553_MDIV_SHIFT 16
726*4882a593Smuzhiyun #define PLL6553_PDIV_SHIFT 8
727*4882a593Smuzhiyun #define PLL6553_SDIV_SHIFT 0
728*4882a593Smuzhiyun #define PLL6553_KDIV_SHIFT 0
729*4882a593Smuzhiyun
samsung_pll6553_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)730*4882a593Smuzhiyun static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
731*4882a593Smuzhiyun unsigned long parent_rate)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
734*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
735*4882a593Smuzhiyun u64 fvco = parent_rate;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
738*4882a593Smuzhiyun pll_con1 = readl_relaxed(pll->con_reg + 0x4);
739*4882a593Smuzhiyun mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
740*4882a593Smuzhiyun pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
741*4882a593Smuzhiyun sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
742*4882a593Smuzhiyun kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun fvco *= (mdiv << 16) + kdiv;
745*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
746*4882a593Smuzhiyun fvco >>= 16;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun return (unsigned long)fvco;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun static const struct clk_ops samsung_pll6553_clk_ops = {
752*4882a593Smuzhiyun .recalc_rate = samsung_pll6553_recalc_rate,
753*4882a593Smuzhiyun };
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun /*
756*4882a593Smuzhiyun * PLL Clock Type of S3C24XX before S3C2443
757*4882a593Smuzhiyun */
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun #define PLLS3C2410_MDIV_MASK (0xff)
760*4882a593Smuzhiyun #define PLLS3C2410_PDIV_MASK (0x1f)
761*4882a593Smuzhiyun #define PLLS3C2410_SDIV_MASK (0x3)
762*4882a593Smuzhiyun #define PLLS3C2410_MDIV_SHIFT (12)
763*4882a593Smuzhiyun #define PLLS3C2410_PDIV_SHIFT (4)
764*4882a593Smuzhiyun #define PLLS3C2410_SDIV_SHIFT (0)
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun #define PLLS3C2410_ENABLE_REG_OFFSET 0x10
767*4882a593Smuzhiyun
samsung_s3c2410_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)768*4882a593Smuzhiyun static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
769*4882a593Smuzhiyun unsigned long parent_rate)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
772*4882a593Smuzhiyun u32 pll_con, mdiv, pdiv, sdiv;
773*4882a593Smuzhiyun u64 fvco = parent_rate;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
776*4882a593Smuzhiyun mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
777*4882a593Smuzhiyun pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
778*4882a593Smuzhiyun sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun fvco *= (mdiv + 8);
781*4882a593Smuzhiyun do_div(fvco, (pdiv + 2) << sdiv);
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun return (unsigned int)fvco;
784*4882a593Smuzhiyun }
785*4882a593Smuzhiyun
samsung_s3c2440_mpll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)786*4882a593Smuzhiyun static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
787*4882a593Smuzhiyun unsigned long parent_rate)
788*4882a593Smuzhiyun {
789*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
790*4882a593Smuzhiyun u32 pll_con, mdiv, pdiv, sdiv;
791*4882a593Smuzhiyun u64 fvco = parent_rate;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
794*4882a593Smuzhiyun mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
795*4882a593Smuzhiyun pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
796*4882a593Smuzhiyun sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun fvco *= (2 * (mdiv + 8));
799*4882a593Smuzhiyun do_div(fvco, (pdiv + 2) << sdiv);
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun return (unsigned int)fvco;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
samsung_s3c2410_pll_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)804*4882a593Smuzhiyun static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
805*4882a593Smuzhiyun unsigned long prate)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
808*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
809*4882a593Smuzhiyun u32 tmp;
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun /* Get required rate settings from table */
812*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
813*4882a593Smuzhiyun if (!rate) {
814*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
815*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
816*4882a593Smuzhiyun return -EINVAL;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun /* Change PLL PMS values */
822*4882a593Smuzhiyun tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
823*4882a593Smuzhiyun (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
824*4882a593Smuzhiyun (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
825*4882a593Smuzhiyun tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
826*4882a593Smuzhiyun (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
827*4882a593Smuzhiyun (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
828*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun /* Time to settle according to the manual */
831*4882a593Smuzhiyun udelay(300);
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun return 0;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun
samsung_s3c2410_pll_enable(struct clk_hw * hw,int bit,bool enable)836*4882a593Smuzhiyun static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
837*4882a593Smuzhiyun {
838*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
839*4882a593Smuzhiyun u32 pll_en = readl_relaxed(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
840*4882a593Smuzhiyun u32 pll_en_orig = pll_en;
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun if (enable)
843*4882a593Smuzhiyun pll_en &= ~BIT(bit);
844*4882a593Smuzhiyun else
845*4882a593Smuzhiyun pll_en |= BIT(bit);
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun writel_relaxed(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
848*4882a593Smuzhiyun
849*4882a593Smuzhiyun /* if we started the UPLL, then allow to settle */
850*4882a593Smuzhiyun if (enable && (pll_en_orig & BIT(bit)))
851*4882a593Smuzhiyun udelay(300);
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun return 0;
854*4882a593Smuzhiyun }
855*4882a593Smuzhiyun
samsung_s3c2410_mpll_enable(struct clk_hw * hw)856*4882a593Smuzhiyun static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
857*4882a593Smuzhiyun {
858*4882a593Smuzhiyun return samsung_s3c2410_pll_enable(hw, 5, true);
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun
samsung_s3c2410_mpll_disable(struct clk_hw * hw)861*4882a593Smuzhiyun static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
862*4882a593Smuzhiyun {
863*4882a593Smuzhiyun samsung_s3c2410_pll_enable(hw, 5, false);
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun
samsung_s3c2410_upll_enable(struct clk_hw * hw)866*4882a593Smuzhiyun static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
867*4882a593Smuzhiyun {
868*4882a593Smuzhiyun return samsung_s3c2410_pll_enable(hw, 7, true);
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
samsung_s3c2410_upll_disable(struct clk_hw * hw)871*4882a593Smuzhiyun static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
872*4882a593Smuzhiyun {
873*4882a593Smuzhiyun samsung_s3c2410_pll_enable(hw, 7, false);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
877*4882a593Smuzhiyun .recalc_rate = samsung_s3c2410_pll_recalc_rate,
878*4882a593Smuzhiyun .enable = samsung_s3c2410_mpll_enable,
879*4882a593Smuzhiyun .disable = samsung_s3c2410_mpll_disable,
880*4882a593Smuzhiyun };
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
883*4882a593Smuzhiyun .recalc_rate = samsung_s3c2410_pll_recalc_rate,
884*4882a593Smuzhiyun .enable = samsung_s3c2410_upll_enable,
885*4882a593Smuzhiyun .disable = samsung_s3c2410_upll_disable,
886*4882a593Smuzhiyun };
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
889*4882a593Smuzhiyun .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
890*4882a593Smuzhiyun .enable = samsung_s3c2410_mpll_enable,
891*4882a593Smuzhiyun .disable = samsung_s3c2410_mpll_disable,
892*4882a593Smuzhiyun };
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
895*4882a593Smuzhiyun .recalc_rate = samsung_s3c2410_pll_recalc_rate,
896*4882a593Smuzhiyun .enable = samsung_s3c2410_mpll_enable,
897*4882a593Smuzhiyun .disable = samsung_s3c2410_mpll_disable,
898*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
899*4882a593Smuzhiyun .set_rate = samsung_s3c2410_pll_set_rate,
900*4882a593Smuzhiyun };
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
903*4882a593Smuzhiyun .recalc_rate = samsung_s3c2410_pll_recalc_rate,
904*4882a593Smuzhiyun .enable = samsung_s3c2410_upll_enable,
905*4882a593Smuzhiyun .disable = samsung_s3c2410_upll_disable,
906*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
907*4882a593Smuzhiyun .set_rate = samsung_s3c2410_pll_set_rate,
908*4882a593Smuzhiyun };
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
911*4882a593Smuzhiyun .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
912*4882a593Smuzhiyun .enable = samsung_s3c2410_mpll_enable,
913*4882a593Smuzhiyun .disable = samsung_s3c2410_mpll_disable,
914*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
915*4882a593Smuzhiyun .set_rate = samsung_s3c2410_pll_set_rate,
916*4882a593Smuzhiyun };
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun /*
919*4882a593Smuzhiyun * PLL2550x Clock Type
920*4882a593Smuzhiyun */
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun #define PLL2550X_R_MASK (0x1)
923*4882a593Smuzhiyun #define PLL2550X_P_MASK (0x3F)
924*4882a593Smuzhiyun #define PLL2550X_M_MASK (0x3FF)
925*4882a593Smuzhiyun #define PLL2550X_S_MASK (0x7)
926*4882a593Smuzhiyun #define PLL2550X_R_SHIFT (20)
927*4882a593Smuzhiyun #define PLL2550X_P_SHIFT (14)
928*4882a593Smuzhiyun #define PLL2550X_M_SHIFT (4)
929*4882a593Smuzhiyun #define PLL2550X_S_SHIFT (0)
930*4882a593Smuzhiyun
samsung_pll2550x_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)931*4882a593Smuzhiyun static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
932*4882a593Smuzhiyun unsigned long parent_rate)
933*4882a593Smuzhiyun {
934*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
935*4882a593Smuzhiyun u32 r, p, m, s, pll_stat;
936*4882a593Smuzhiyun u64 fvco = parent_rate;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun pll_stat = readl_relaxed(pll->con_reg);
939*4882a593Smuzhiyun r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
940*4882a593Smuzhiyun if (!r)
941*4882a593Smuzhiyun return 0;
942*4882a593Smuzhiyun p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
943*4882a593Smuzhiyun m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
944*4882a593Smuzhiyun s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun fvco *= m;
947*4882a593Smuzhiyun do_div(fvco, (p << s));
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun return (unsigned long)fvco;
950*4882a593Smuzhiyun }
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun static const struct clk_ops samsung_pll2550x_clk_ops = {
953*4882a593Smuzhiyun .recalc_rate = samsung_pll2550x_recalc_rate,
954*4882a593Smuzhiyun };
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun /*
957*4882a593Smuzhiyun * PLL2550xx Clock Type
958*4882a593Smuzhiyun */
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun /* Maximum lock time can be 270 * PDIV cycles */
961*4882a593Smuzhiyun #define PLL2550XX_LOCK_FACTOR 270
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun #define PLL2550XX_M_MASK 0x3FF
964*4882a593Smuzhiyun #define PLL2550XX_P_MASK 0x3F
965*4882a593Smuzhiyun #define PLL2550XX_S_MASK 0x7
966*4882a593Smuzhiyun #define PLL2550XX_LOCK_STAT_MASK 0x1
967*4882a593Smuzhiyun #define PLL2550XX_M_SHIFT 9
968*4882a593Smuzhiyun #define PLL2550XX_P_SHIFT 3
969*4882a593Smuzhiyun #define PLL2550XX_S_SHIFT 0
970*4882a593Smuzhiyun #define PLL2550XX_LOCK_STAT_SHIFT 21
971*4882a593Smuzhiyun
samsung_pll2550xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)972*4882a593Smuzhiyun static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
973*4882a593Smuzhiyun unsigned long parent_rate)
974*4882a593Smuzhiyun {
975*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
976*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con;
977*4882a593Smuzhiyun u64 fvco = parent_rate;
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun pll_con = readl_relaxed(pll->con_reg);
980*4882a593Smuzhiyun mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
981*4882a593Smuzhiyun pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
982*4882a593Smuzhiyun sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
983*4882a593Smuzhiyun
984*4882a593Smuzhiyun fvco *= mdiv;
985*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun return (unsigned long)fvco;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
samsung_pll2550xx_mp_change(u32 mdiv,u32 pdiv,u32 pll_con)990*4882a593Smuzhiyun static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun u32 old_mdiv, old_pdiv;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
995*4882a593Smuzhiyun old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun return mdiv != old_mdiv || pdiv != old_pdiv;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun
samsung_pll2550xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)1000*4882a593Smuzhiyun static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
1001*4882a593Smuzhiyun unsigned long prate)
1002*4882a593Smuzhiyun {
1003*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
1004*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
1005*4882a593Smuzhiyun u32 tmp;
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun /* Get required rate settings from table */
1008*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
1009*4882a593Smuzhiyun if (!rate) {
1010*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1011*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
1012*4882a593Smuzhiyun return -EINVAL;
1013*4882a593Smuzhiyun }
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1018*4882a593Smuzhiyun /* If only s change, change just s value only*/
1019*4882a593Smuzhiyun tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1020*4882a593Smuzhiyun tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1021*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun return 0;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun /* Set PLL lock time. */
1027*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun /* Change PLL PMS values */
1030*4882a593Smuzhiyun tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1031*4882a593Smuzhiyun (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1032*4882a593Smuzhiyun (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1033*4882a593Smuzhiyun tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1034*4882a593Smuzhiyun (rate->pdiv << PLL2550XX_P_SHIFT) |
1035*4882a593Smuzhiyun (rate->sdiv << PLL2550XX_S_SHIFT);
1036*4882a593Smuzhiyun writel_relaxed(tmp, pll->con_reg);
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun /* wait_lock_time */
1039*4882a593Smuzhiyun do {
1040*4882a593Smuzhiyun cpu_relax();
1041*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
1042*4882a593Smuzhiyun } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1043*4882a593Smuzhiyun << PLL2550XX_LOCK_STAT_SHIFT)));
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun return 0;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun static const struct clk_ops samsung_pll2550xx_clk_ops = {
1049*4882a593Smuzhiyun .recalc_rate = samsung_pll2550xx_recalc_rate,
1050*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
1051*4882a593Smuzhiyun .set_rate = samsung_pll2550xx_set_rate,
1052*4882a593Smuzhiyun };
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1055*4882a593Smuzhiyun .recalc_rate = samsung_pll2550xx_recalc_rate,
1056*4882a593Smuzhiyun };
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun /*
1059*4882a593Smuzhiyun * PLL2650x Clock Type
1060*4882a593Smuzhiyun */
1061*4882a593Smuzhiyun
1062*4882a593Smuzhiyun /* Maximum lock time can be 3000 * PDIV cycles */
1063*4882a593Smuzhiyun #define PLL2650X_LOCK_FACTOR 3000
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun #define PLL2650X_M_MASK 0x1ff
1066*4882a593Smuzhiyun #define PLL2650X_P_MASK 0x3f
1067*4882a593Smuzhiyun #define PLL2650X_S_MASK 0x7
1068*4882a593Smuzhiyun #define PLL2650X_K_MASK 0xffff
1069*4882a593Smuzhiyun #define PLL2650X_LOCK_STAT_MASK 0x1
1070*4882a593Smuzhiyun #define PLL2650X_M_SHIFT 16
1071*4882a593Smuzhiyun #define PLL2650X_P_SHIFT 8
1072*4882a593Smuzhiyun #define PLL2650X_S_SHIFT 0
1073*4882a593Smuzhiyun #define PLL2650X_K_SHIFT 0
1074*4882a593Smuzhiyun #define PLL2650X_LOCK_STAT_SHIFT 29
1075*4882a593Smuzhiyun #define PLL2650X_PLL_ENABLE_SHIFT 31
1076*4882a593Smuzhiyun
samsung_pll2650x_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)1077*4882a593Smuzhiyun static unsigned long samsung_pll2650x_recalc_rate(struct clk_hw *hw,
1078*4882a593Smuzhiyun unsigned long parent_rate)
1079*4882a593Smuzhiyun {
1080*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
1081*4882a593Smuzhiyun u64 fout = parent_rate;
1082*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
1083*4882a593Smuzhiyun s16 kdiv;
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
1086*4882a593Smuzhiyun mdiv = (pll_con0 >> PLL2650X_M_SHIFT) & PLL2650X_M_MASK;
1087*4882a593Smuzhiyun pdiv = (pll_con0 >> PLL2650X_P_SHIFT) & PLL2650X_P_MASK;
1088*4882a593Smuzhiyun sdiv = (pll_con0 >> PLL2650X_S_SHIFT) & PLL2650X_S_MASK;
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun pll_con1 = readl_relaxed(pll->con_reg + 4);
1091*4882a593Smuzhiyun kdiv = (s16)((pll_con1 >> PLL2650X_K_SHIFT) & PLL2650X_K_MASK);
1092*4882a593Smuzhiyun
1093*4882a593Smuzhiyun fout *= (mdiv << 16) + kdiv;
1094*4882a593Smuzhiyun do_div(fout, (pdiv << sdiv));
1095*4882a593Smuzhiyun fout >>= 16;
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun return (unsigned long)fout;
1098*4882a593Smuzhiyun }
1099*4882a593Smuzhiyun
samsung_pll2650x_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long prate)1100*4882a593Smuzhiyun static int samsung_pll2650x_set_rate(struct clk_hw *hw, unsigned long drate,
1101*4882a593Smuzhiyun unsigned long prate)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
1104*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
1105*4882a593Smuzhiyun u32 con0, con1;
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun /* Get required rate settings from table */
1108*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
1109*4882a593Smuzhiyun if (!rate) {
1110*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1111*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
1112*4882a593Smuzhiyun return -EINVAL;
1113*4882a593Smuzhiyun }
1114*4882a593Smuzhiyun
1115*4882a593Smuzhiyun con0 = readl_relaxed(pll->con_reg);
1116*4882a593Smuzhiyun con1 = readl_relaxed(pll->con_reg + 4);
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun /* Set PLL lock time. */
1119*4882a593Smuzhiyun writel_relaxed(rate->pdiv * PLL2650X_LOCK_FACTOR, pll->lock_reg);
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun /* Change PLL PMS values */
1122*4882a593Smuzhiyun con0 &= ~((PLL2650X_M_MASK << PLL2650X_M_SHIFT) |
1123*4882a593Smuzhiyun (PLL2650X_P_MASK << PLL2650X_P_SHIFT) |
1124*4882a593Smuzhiyun (PLL2650X_S_MASK << PLL2650X_S_SHIFT));
1125*4882a593Smuzhiyun con0 |= (rate->mdiv << PLL2650X_M_SHIFT) |
1126*4882a593Smuzhiyun (rate->pdiv << PLL2650X_P_SHIFT) |
1127*4882a593Smuzhiyun (rate->sdiv << PLL2650X_S_SHIFT);
1128*4882a593Smuzhiyun con0 |= (1 << PLL2650X_PLL_ENABLE_SHIFT);
1129*4882a593Smuzhiyun writel_relaxed(con0, pll->con_reg);
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun con1 &= ~(PLL2650X_K_MASK << PLL2650X_K_SHIFT);
1132*4882a593Smuzhiyun con1 |= ((rate->kdiv & PLL2650X_K_MASK) << PLL2650X_K_SHIFT);
1133*4882a593Smuzhiyun writel_relaxed(con1, pll->con_reg + 4);
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun do {
1136*4882a593Smuzhiyun cpu_relax();
1137*4882a593Smuzhiyun con0 = readl_relaxed(pll->con_reg);
1138*4882a593Smuzhiyun } while (!(con0 & (PLL2650X_LOCK_STAT_MASK
1139*4882a593Smuzhiyun << PLL2650X_LOCK_STAT_SHIFT)));
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun return 0;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun static const struct clk_ops samsung_pll2650x_clk_ops = {
1145*4882a593Smuzhiyun .recalc_rate = samsung_pll2650x_recalc_rate,
1146*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
1147*4882a593Smuzhiyun .set_rate = samsung_pll2650x_set_rate,
1148*4882a593Smuzhiyun };
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun static const struct clk_ops samsung_pll2650x_clk_min_ops = {
1151*4882a593Smuzhiyun .recalc_rate = samsung_pll2650x_recalc_rate,
1152*4882a593Smuzhiyun };
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun /*
1155*4882a593Smuzhiyun * PLL2650XX Clock Type
1156*4882a593Smuzhiyun */
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun /* Maximum lock time can be 3000 * PDIV cycles */
1159*4882a593Smuzhiyun #define PLL2650XX_LOCK_FACTOR 3000
1160*4882a593Smuzhiyun
1161*4882a593Smuzhiyun #define PLL2650XX_MDIV_SHIFT 9
1162*4882a593Smuzhiyun #define PLL2650XX_PDIV_SHIFT 3
1163*4882a593Smuzhiyun #define PLL2650XX_SDIV_SHIFT 0
1164*4882a593Smuzhiyun #define PLL2650XX_KDIV_SHIFT 0
1165*4882a593Smuzhiyun #define PLL2650XX_MDIV_MASK 0x1ff
1166*4882a593Smuzhiyun #define PLL2650XX_PDIV_MASK 0x3f
1167*4882a593Smuzhiyun #define PLL2650XX_SDIV_MASK 0x7
1168*4882a593Smuzhiyun #define PLL2650XX_KDIV_MASK 0xffff
1169*4882a593Smuzhiyun #define PLL2650XX_PLL_ENABLE_SHIFT 23
1170*4882a593Smuzhiyun #define PLL2650XX_PLL_LOCKTIME_SHIFT 21
1171*4882a593Smuzhiyun #define PLL2650XX_PLL_FOUTMASK_SHIFT 31
1172*4882a593Smuzhiyun
samsung_pll2650xx_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)1173*4882a593Smuzhiyun static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1174*4882a593Smuzhiyun unsigned long parent_rate)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
1177*4882a593Smuzhiyun u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1178*4882a593Smuzhiyun s16 kdiv;
1179*4882a593Smuzhiyun u64 fvco = parent_rate;
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
1182*4882a593Smuzhiyun pll_con2 = readl_relaxed(pll->con_reg + 8);
1183*4882a593Smuzhiyun mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1184*4882a593Smuzhiyun pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1185*4882a593Smuzhiyun sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1186*4882a593Smuzhiyun kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun fvco *= (mdiv << 16) + kdiv;
1189*4882a593Smuzhiyun do_div(fvco, (pdiv << sdiv));
1190*4882a593Smuzhiyun fvco >>= 16;
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun return (unsigned long)fvco;
1193*4882a593Smuzhiyun }
1194*4882a593Smuzhiyun
samsung_pll2650xx_set_rate(struct clk_hw * hw,unsigned long drate,unsigned long parent_rate)1195*4882a593Smuzhiyun static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1196*4882a593Smuzhiyun unsigned long parent_rate)
1197*4882a593Smuzhiyun {
1198*4882a593Smuzhiyun struct samsung_clk_pll *pll = to_clk_pll(hw);
1199*4882a593Smuzhiyun u32 tmp, pll_con0, pll_con2;
1200*4882a593Smuzhiyun const struct samsung_pll_rate_table *rate;
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun rate = samsung_get_pll_settings(pll, drate);
1203*4882a593Smuzhiyun if (!rate) {
1204*4882a593Smuzhiyun pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1205*4882a593Smuzhiyun drate, clk_hw_get_name(hw));
1206*4882a593Smuzhiyun return -EINVAL;
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun pll_con0 = readl_relaxed(pll->con_reg);
1210*4882a593Smuzhiyun pll_con2 = readl_relaxed(pll->con_reg + 8);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun /* Change PLL PMS values */
1213*4882a593Smuzhiyun pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1214*4882a593Smuzhiyun PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1215*4882a593Smuzhiyun PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1216*4882a593Smuzhiyun pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1217*4882a593Smuzhiyun pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1218*4882a593Smuzhiyun pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1219*4882a593Smuzhiyun pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1220*4882a593Smuzhiyun pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1223*4882a593Smuzhiyun pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1224*4882a593Smuzhiyun << PLL2650XX_KDIV_SHIFT;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun /* Set PLL lock time. */
1227*4882a593Smuzhiyun writel_relaxed(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1228*4882a593Smuzhiyun
1229*4882a593Smuzhiyun writel_relaxed(pll_con0, pll->con_reg);
1230*4882a593Smuzhiyun writel_relaxed(pll_con2, pll->con_reg + 8);
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun do {
1233*4882a593Smuzhiyun tmp = readl_relaxed(pll->con_reg);
1234*4882a593Smuzhiyun } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun return 0;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
1239*4882a593Smuzhiyun static const struct clk_ops samsung_pll2650xx_clk_ops = {
1240*4882a593Smuzhiyun .recalc_rate = samsung_pll2650xx_recalc_rate,
1241*4882a593Smuzhiyun .set_rate = samsung_pll2650xx_set_rate,
1242*4882a593Smuzhiyun .round_rate = samsung_pll_round_rate,
1243*4882a593Smuzhiyun };
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1246*4882a593Smuzhiyun .recalc_rate = samsung_pll2650xx_recalc_rate,
1247*4882a593Smuzhiyun };
1248*4882a593Smuzhiyun
_samsung_clk_register_pll(struct samsung_clk_provider * ctx,const struct samsung_pll_clock * pll_clk,void __iomem * base)1249*4882a593Smuzhiyun static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1250*4882a593Smuzhiyun const struct samsung_pll_clock *pll_clk,
1251*4882a593Smuzhiyun void __iomem *base)
1252*4882a593Smuzhiyun {
1253*4882a593Smuzhiyun struct samsung_clk_pll *pll;
1254*4882a593Smuzhiyun struct clk_init_data init;
1255*4882a593Smuzhiyun int ret, len;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun pll = kzalloc(sizeof(*pll), GFP_KERNEL);
1258*4882a593Smuzhiyun if (!pll) {
1259*4882a593Smuzhiyun pr_err("%s: could not allocate pll clk %s\n",
1260*4882a593Smuzhiyun __func__, pll_clk->name);
1261*4882a593Smuzhiyun return;
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun init.name = pll_clk->name;
1265*4882a593Smuzhiyun init.flags = pll_clk->flags;
1266*4882a593Smuzhiyun init.parent_names = &pll_clk->parent_name;
1267*4882a593Smuzhiyun init.num_parents = 1;
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun if (pll_clk->rate_table) {
1270*4882a593Smuzhiyun /* find count of rates in rate_table */
1271*4882a593Smuzhiyun for (len = 0; pll_clk->rate_table[len].rate != 0; )
1272*4882a593Smuzhiyun len++;
1273*4882a593Smuzhiyun
1274*4882a593Smuzhiyun pll->rate_count = len;
1275*4882a593Smuzhiyun pll->rate_table = kmemdup(pll_clk->rate_table,
1276*4882a593Smuzhiyun pll->rate_count *
1277*4882a593Smuzhiyun sizeof(struct samsung_pll_rate_table),
1278*4882a593Smuzhiyun GFP_KERNEL);
1279*4882a593Smuzhiyun WARN(!pll->rate_table,
1280*4882a593Smuzhiyun "%s: could not allocate rate table for %s\n",
1281*4882a593Smuzhiyun __func__, pll_clk->name);
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun switch (pll_clk->type) {
1285*4882a593Smuzhiyun case pll_2126:
1286*4882a593Smuzhiyun init.ops = &samsung_pll2126_clk_ops;
1287*4882a593Smuzhiyun break;
1288*4882a593Smuzhiyun case pll_3000:
1289*4882a593Smuzhiyun init.ops = &samsung_pll3000_clk_ops;
1290*4882a593Smuzhiyun break;
1291*4882a593Smuzhiyun /* clk_ops for 35xx and 2550 are similar */
1292*4882a593Smuzhiyun case pll_35xx:
1293*4882a593Smuzhiyun case pll_2550:
1294*4882a593Smuzhiyun case pll_1450x:
1295*4882a593Smuzhiyun case pll_1451x:
1296*4882a593Smuzhiyun case pll_1452x:
1297*4882a593Smuzhiyun pll->enable_offs = PLL35XX_ENABLE_SHIFT;
1298*4882a593Smuzhiyun pll->lock_offs = PLL35XX_LOCK_STAT_SHIFT;
1299*4882a593Smuzhiyun if (!pll->rate_table)
1300*4882a593Smuzhiyun init.ops = &samsung_pll35xx_clk_min_ops;
1301*4882a593Smuzhiyun else
1302*4882a593Smuzhiyun init.ops = &samsung_pll35xx_clk_ops;
1303*4882a593Smuzhiyun break;
1304*4882a593Smuzhiyun case pll_4500:
1305*4882a593Smuzhiyun init.ops = &samsung_pll45xx_clk_min_ops;
1306*4882a593Smuzhiyun break;
1307*4882a593Smuzhiyun case pll_4502:
1308*4882a593Smuzhiyun case pll_4508:
1309*4882a593Smuzhiyun if (!pll->rate_table)
1310*4882a593Smuzhiyun init.ops = &samsung_pll45xx_clk_min_ops;
1311*4882a593Smuzhiyun else
1312*4882a593Smuzhiyun init.ops = &samsung_pll45xx_clk_ops;
1313*4882a593Smuzhiyun break;
1314*4882a593Smuzhiyun /* clk_ops for 36xx and 2650 are similar */
1315*4882a593Smuzhiyun case pll_36xx:
1316*4882a593Smuzhiyun case pll_2650:
1317*4882a593Smuzhiyun pll->enable_offs = PLL36XX_ENABLE_SHIFT;
1318*4882a593Smuzhiyun pll->lock_offs = PLL36XX_LOCK_STAT_SHIFT;
1319*4882a593Smuzhiyun if (!pll->rate_table)
1320*4882a593Smuzhiyun init.ops = &samsung_pll36xx_clk_min_ops;
1321*4882a593Smuzhiyun else
1322*4882a593Smuzhiyun init.ops = &samsung_pll36xx_clk_ops;
1323*4882a593Smuzhiyun break;
1324*4882a593Smuzhiyun case pll_6552:
1325*4882a593Smuzhiyun case pll_6552_s3c2416:
1326*4882a593Smuzhiyun init.ops = &samsung_pll6552_clk_ops;
1327*4882a593Smuzhiyun break;
1328*4882a593Smuzhiyun case pll_6553:
1329*4882a593Smuzhiyun init.ops = &samsung_pll6553_clk_ops;
1330*4882a593Smuzhiyun break;
1331*4882a593Smuzhiyun case pll_4600:
1332*4882a593Smuzhiyun case pll_4650:
1333*4882a593Smuzhiyun case pll_4650c:
1334*4882a593Smuzhiyun case pll_1460x:
1335*4882a593Smuzhiyun if (!pll->rate_table)
1336*4882a593Smuzhiyun init.ops = &samsung_pll46xx_clk_min_ops;
1337*4882a593Smuzhiyun else
1338*4882a593Smuzhiyun init.ops = &samsung_pll46xx_clk_ops;
1339*4882a593Smuzhiyun break;
1340*4882a593Smuzhiyun case pll_s3c2410_mpll:
1341*4882a593Smuzhiyun if (!pll->rate_table)
1342*4882a593Smuzhiyun init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1343*4882a593Smuzhiyun else
1344*4882a593Smuzhiyun init.ops = &samsung_s3c2410_mpll_clk_ops;
1345*4882a593Smuzhiyun break;
1346*4882a593Smuzhiyun case pll_s3c2410_upll:
1347*4882a593Smuzhiyun if (!pll->rate_table)
1348*4882a593Smuzhiyun init.ops = &samsung_s3c2410_upll_clk_min_ops;
1349*4882a593Smuzhiyun else
1350*4882a593Smuzhiyun init.ops = &samsung_s3c2410_upll_clk_ops;
1351*4882a593Smuzhiyun break;
1352*4882a593Smuzhiyun case pll_s3c2440_mpll:
1353*4882a593Smuzhiyun if (!pll->rate_table)
1354*4882a593Smuzhiyun init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1355*4882a593Smuzhiyun else
1356*4882a593Smuzhiyun init.ops = &samsung_s3c2440_mpll_clk_ops;
1357*4882a593Smuzhiyun break;
1358*4882a593Smuzhiyun case pll_2550x:
1359*4882a593Smuzhiyun init.ops = &samsung_pll2550x_clk_ops;
1360*4882a593Smuzhiyun break;
1361*4882a593Smuzhiyun case pll_2550xx:
1362*4882a593Smuzhiyun if (!pll->rate_table)
1363*4882a593Smuzhiyun init.ops = &samsung_pll2550xx_clk_min_ops;
1364*4882a593Smuzhiyun else
1365*4882a593Smuzhiyun init.ops = &samsung_pll2550xx_clk_ops;
1366*4882a593Smuzhiyun break;
1367*4882a593Smuzhiyun case pll_2650x:
1368*4882a593Smuzhiyun if (!pll->rate_table)
1369*4882a593Smuzhiyun init.ops = &samsung_pll2650x_clk_min_ops;
1370*4882a593Smuzhiyun else
1371*4882a593Smuzhiyun init.ops = &samsung_pll2650x_clk_ops;
1372*4882a593Smuzhiyun break;
1373*4882a593Smuzhiyun case pll_2650xx:
1374*4882a593Smuzhiyun if (!pll->rate_table)
1375*4882a593Smuzhiyun init.ops = &samsung_pll2650xx_clk_min_ops;
1376*4882a593Smuzhiyun else
1377*4882a593Smuzhiyun init.ops = &samsung_pll2650xx_clk_ops;
1378*4882a593Smuzhiyun break;
1379*4882a593Smuzhiyun default:
1380*4882a593Smuzhiyun pr_warn("%s: Unknown pll type for pll clk %s\n",
1381*4882a593Smuzhiyun __func__, pll_clk->name);
1382*4882a593Smuzhiyun }
1383*4882a593Smuzhiyun
1384*4882a593Smuzhiyun pll->hw.init = &init;
1385*4882a593Smuzhiyun pll->type = pll_clk->type;
1386*4882a593Smuzhiyun pll->lock_reg = base + pll_clk->lock_offset;
1387*4882a593Smuzhiyun pll->con_reg = base + pll_clk->con_offset;
1388*4882a593Smuzhiyun
1389*4882a593Smuzhiyun ret = clk_hw_register(ctx->dev, &pll->hw);
1390*4882a593Smuzhiyun if (ret) {
1391*4882a593Smuzhiyun pr_err("%s: failed to register pll clock %s : %d\n",
1392*4882a593Smuzhiyun __func__, pll_clk->name, ret);
1393*4882a593Smuzhiyun kfree(pll);
1394*4882a593Smuzhiyun return;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun samsung_clk_add_lookup(ctx, &pll->hw, pll_clk->id);
1398*4882a593Smuzhiyun }
1399*4882a593Smuzhiyun
samsung_clk_register_pll(struct samsung_clk_provider * ctx,const struct samsung_pll_clock * pll_list,unsigned int nr_pll,void __iomem * base)1400*4882a593Smuzhiyun void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1401*4882a593Smuzhiyun const struct samsung_pll_clock *pll_list,
1402*4882a593Smuzhiyun unsigned int nr_pll, void __iomem *base)
1403*4882a593Smuzhiyun {
1404*4882a593Smuzhiyun int cnt;
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun for (cnt = 0; cnt < nr_pll; cnt++)
1407*4882a593Smuzhiyun _samsung_clk_register_pll(ctx, &pll_list[cnt], base);
1408*4882a593Smuzhiyun }
1409