blob: bebc61b5fce1f3741200bf146e6dd059a222f5b9 [file] [log] [blame]
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +09001/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2013 Linaro Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This file contains the utility functions to register the pll clocks.
10*/
11
12#include <linux/errno.h>
Tomasz Figab4054ac2013-08-26 19:09:05 +020013#include <linux/hrtimer.h>
Heiko Stuebnerea5d6a82014-02-25 09:50:43 +090014#include <linux/delay.h>
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090015#include "clk.h"
16#include "clk-pll.h"
17
Tomasz Figab4054ac2013-08-26 19:09:05 +020018#define PLL_TIMEOUT_MS 10
19
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +053020struct samsung_clk_pll {
21 struct clk_hw hw;
22 void __iomem *lock_reg;
23 void __iomem *con_reg;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +053024 enum samsung_pll_type type;
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +053025 unsigned int rate_count;
26 const struct samsung_pll_rate_table *rate_table;
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +053027};
28
29#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
30
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +053031static const struct samsung_pll_rate_table *samsung_get_pll_settings(
32 struct samsung_clk_pll *pll, unsigned long rate)
33{
34 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
35 int i;
36
37 for (i = 0; i < pll->rate_count; i++) {
38 if (rate == rate_table[i].rate)
39 return &rate_table[i];
40 }
41
42 return NULL;
43}
44
45static long samsung_pll_round_rate(struct clk_hw *hw,
46 unsigned long drate, unsigned long *prate)
47{
48 struct samsung_clk_pll *pll = to_clk_pll(hw);
49 const struct samsung_pll_rate_table *rate_table = pll->rate_table;
50 int i;
51
52 /* Assumming rate_table is in descending order */
53 for (i = 0; i < pll->rate_count; i++) {
54 if (drate >= rate_table[i].rate)
55 return rate_table[i].rate;
56 }
57
58 /* return minimum supported value */
59 return rate_table[i - 1].rate;
60}
61
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +090062/*
Heiko Stuebnera951b1d2014-02-19 09:25:41 +090063 * PLL2126 Clock Type
64 */
65
66#define PLL2126_MDIV_MASK (0xff)
67#define PLL2126_PDIV_MASK (0x3f)
68#define PLL2126_SDIV_MASK (0x3)
69#define PLL2126_MDIV_SHIFT (16)
70#define PLL2126_PDIV_SHIFT (8)
71#define PLL2126_SDIV_SHIFT (0)
72
73static unsigned long samsung_pll2126_recalc_rate(struct clk_hw *hw,
74 unsigned long parent_rate)
75{
76 struct samsung_clk_pll *pll = to_clk_pll(hw);
77 u32 pll_con, mdiv, pdiv, sdiv;
78 u64 fvco = parent_rate;
79
80 pll_con = __raw_readl(pll->con_reg);
81 mdiv = (pll_con >> PLL2126_MDIV_SHIFT) & PLL2126_MDIV_MASK;
82 pdiv = (pll_con >> PLL2126_PDIV_SHIFT) & PLL2126_PDIV_MASK;
83 sdiv = (pll_con >> PLL2126_SDIV_SHIFT) & PLL2126_SDIV_MASK;
84
85 fvco *= (mdiv + 8);
86 do_div(fvco, (pdiv + 2) << sdiv);
87
88 return (unsigned long)fvco;
89}
90
91static const struct clk_ops samsung_pll2126_clk_ops = {
92 .recalc_rate = samsung_pll2126_recalc_rate,
93};
94
95/*
96 * PLL3000 Clock Type
97 */
98
99#define PLL3000_MDIV_MASK (0xff)
100#define PLL3000_PDIV_MASK (0x3)
101#define PLL3000_SDIV_MASK (0x3)
102#define PLL3000_MDIV_SHIFT (16)
103#define PLL3000_PDIV_SHIFT (8)
104#define PLL3000_SDIV_SHIFT (0)
105
106static unsigned long samsung_pll3000_recalc_rate(struct clk_hw *hw,
107 unsigned long parent_rate)
108{
109 struct samsung_clk_pll *pll = to_clk_pll(hw);
110 u32 pll_con, mdiv, pdiv, sdiv;
111 u64 fvco = parent_rate;
112
113 pll_con = __raw_readl(pll->con_reg);
114 mdiv = (pll_con >> PLL3000_MDIV_SHIFT) & PLL3000_MDIV_MASK;
115 pdiv = (pll_con >> PLL3000_PDIV_SHIFT) & PLL3000_PDIV_MASK;
116 sdiv = (pll_con >> PLL3000_SDIV_SHIFT) & PLL3000_SDIV_MASK;
117
118 fvco *= (2 * (mdiv + 8));
119 do_div(fvco, pdiv << sdiv);
120
121 return (unsigned long)fvco;
122}
123
124static const struct clk_ops samsung_pll3000_clk_ops = {
125 .recalc_rate = samsung_pll3000_recalc_rate,
126};
127
128/*
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900129 * PLL35xx Clock Type
130 */
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530131/* Maximum lock time can be 270 * PDIV cycles */
132#define PLL35XX_LOCK_FACTOR (270)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900133
134#define PLL35XX_MDIV_MASK (0x3FF)
135#define PLL35XX_PDIV_MASK (0x3F)
136#define PLL35XX_SDIV_MASK (0x7)
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530137#define PLL35XX_LOCK_STAT_MASK (0x1)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900138#define PLL35XX_MDIV_SHIFT (16)
139#define PLL35XX_PDIV_SHIFT (8)
140#define PLL35XX_SDIV_SHIFT (0)
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530141#define PLL35XX_LOCK_STAT_SHIFT (29)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900142
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900143static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
144 unsigned long parent_rate)
145{
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +0530146 struct samsung_clk_pll *pll = to_clk_pll(hw);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900147 u32 mdiv, pdiv, sdiv, pll_con;
148 u64 fvco = parent_rate;
149
150 pll_con = __raw_readl(pll->con_reg);
151 mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
152 pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
153 sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
154
155 fvco *= mdiv;
156 do_div(fvco, (pdiv << sdiv));
157
158 return (unsigned long)fvco;
159}
160
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530161static inline bool samsung_pll35xx_mp_change(
162 const struct samsung_pll_rate_table *rate, u32 pll_con)
163{
164 u32 old_mdiv, old_pdiv;
165
166 old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
167 old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
168
169 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
170}
171
172static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
173 unsigned long prate)
174{
175 struct samsung_clk_pll *pll = to_clk_pll(hw);
176 const struct samsung_pll_rate_table *rate;
177 u32 tmp;
178
179 /* Get required rate settings from table */
180 rate = samsung_get_pll_settings(pll, drate);
181 if (!rate) {
182 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
183 drate, __clk_get_name(hw->clk));
184 return -EINVAL;
185 }
186
187 tmp = __raw_readl(pll->con_reg);
188
189 if (!(samsung_pll35xx_mp_change(rate, tmp))) {
190 /* If only s change, change just s value only*/
191 tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
192 tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
193 __raw_writel(tmp, pll->con_reg);
194
195 return 0;
196 }
197
198 /* Set PLL lock time. */
199 __raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
200 pll->lock_reg);
201
202 /* Change PLL PMS values */
203 tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
204 (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
205 (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
206 tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
207 (rate->pdiv << PLL35XX_PDIV_SHIFT) |
208 (rate->sdiv << PLL35XX_SDIV_SHIFT);
209 __raw_writel(tmp, pll->con_reg);
210
211 /* wait_lock_time */
212 do {
213 cpu_relax();
214 tmp = __raw_readl(pll->con_reg);
215 } while (!(tmp & (PLL35XX_LOCK_STAT_MASK
216 << PLL35XX_LOCK_STAT_SHIFT)));
217 return 0;
218}
219
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900220static const struct clk_ops samsung_pll35xx_clk_ops = {
221 .recalc_rate = samsung_pll35xx_recalc_rate,
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +0530222 .round_rate = samsung_pll_round_rate,
223 .set_rate = samsung_pll35xx_set_rate,
224};
225
226static const struct clk_ops samsung_pll35xx_clk_min_ops = {
227 .recalc_rate = samsung_pll35xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900228};
229
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900230/*
231 * PLL36xx Clock Type
232 */
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530233/* Maximum lock time can be 3000 * PDIV cycles */
234#define PLL36XX_LOCK_FACTOR (3000)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900235
236#define PLL36XX_KDIV_MASK (0xFFFF)
237#define PLL36XX_MDIV_MASK (0x1FF)
238#define PLL36XX_PDIV_MASK (0x3F)
239#define PLL36XX_SDIV_MASK (0x7)
240#define PLL36XX_MDIV_SHIFT (16)
241#define PLL36XX_PDIV_SHIFT (8)
242#define PLL36XX_SDIV_SHIFT (0)
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530243#define PLL36XX_KDIV_SHIFT (0)
244#define PLL36XX_LOCK_STAT_SHIFT (29)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900245
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900246static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
247 unsigned long parent_rate)
248{
Yadwinder Singh Brar079dbea2013-06-11 15:01:06 +0530249 struct samsung_clk_pll *pll = to_clk_pll(hw);
Doug Anderson071ff9a2013-06-11 08:24:05 -0700250 u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
251 s16 kdiv;
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900252 u64 fvco = parent_rate;
253
254 pll_con0 = __raw_readl(pll->con_reg);
255 pll_con1 = __raw_readl(pll->con_reg + 4);
256 mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
257 pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
258 sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
Doug Anderson071ff9a2013-06-11 08:24:05 -0700259 kdiv = (s16)(pll_con1 & PLL36XX_KDIV_MASK);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900260
261 fvco *= (mdiv << 16) + kdiv;
262 do_div(fvco, (pdiv << sdiv));
263 fvco >>= 16;
264
265 return (unsigned long)fvco;
266}
267
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530268static inline bool samsung_pll36xx_mpk_change(
269 const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
270{
271 u32 old_mdiv, old_pdiv, old_kdiv;
272
273 old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
274 old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
275 old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
276
277 return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
278 rate->kdiv != old_kdiv);
279}
280
281static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
282 unsigned long parent_rate)
283{
284 struct samsung_clk_pll *pll = to_clk_pll(hw);
285 u32 tmp, pll_con0, pll_con1;
286 const struct samsung_pll_rate_table *rate;
287
288 rate = samsung_get_pll_settings(pll, drate);
289 if (!rate) {
290 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
291 drate, __clk_get_name(hw->clk));
292 return -EINVAL;
293 }
294
295 pll_con0 = __raw_readl(pll->con_reg);
296 pll_con1 = __raw_readl(pll->con_reg + 4);
297
298 if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
299 /* If only s change, change just s value only*/
300 pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
301 pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
302 __raw_writel(pll_con0, pll->con_reg);
303
304 return 0;
305 }
306
307 /* Set PLL lock time. */
308 __raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
309
310 /* Change PLL PMS values */
311 pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
312 (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
313 (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
314 pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
315 (rate->pdiv << PLL36XX_PDIV_SHIFT) |
316 (rate->sdiv << PLL36XX_SDIV_SHIFT);
317 __raw_writel(pll_con0, pll->con_reg);
318
319 pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
320 pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
321 __raw_writel(pll_con1, pll->con_reg + 4);
322
323 /* wait_lock_time */
324 do {
325 cpu_relax();
326 tmp = __raw_readl(pll->con_reg);
327 } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
328
329 return 0;
330}
331
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900332static const struct clk_ops samsung_pll36xx_clk_ops = {
333 .recalc_rate = samsung_pll36xx_recalc_rate,
Vikas Sajjanbb4278d2013-06-11 15:01:14 +0530334 .set_rate = samsung_pll36xx_set_rate,
335 .round_rate = samsung_pll_round_rate,
336};
337
338static const struct clk_ops samsung_pll36xx_clk_min_ops = {
339 .recalc_rate = samsung_pll36xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900340};
341
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900342/*
343 * PLL45xx Clock Type
344 */
Tomasz Figab4054ac2013-08-26 19:09:05 +0200345#define PLL4502_LOCK_FACTOR 400
346#define PLL4508_LOCK_FACTOR 240
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900347
348#define PLL45XX_MDIV_MASK (0x3FF)
349#define PLL45XX_PDIV_MASK (0x3F)
350#define PLL45XX_SDIV_MASK (0x7)
Tomasz Figab4054ac2013-08-26 19:09:05 +0200351#define PLL45XX_AFC_MASK (0x1F)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900352#define PLL45XX_MDIV_SHIFT (16)
353#define PLL45XX_PDIV_SHIFT (8)
354#define PLL45XX_SDIV_SHIFT (0)
Tomasz Figab4054ac2013-08-26 19:09:05 +0200355#define PLL45XX_AFC_SHIFT (0)
356
357#define PLL45XX_ENABLE BIT(31)
358#define PLL45XX_LOCKED BIT(29)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900359
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900360static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
361 unsigned long parent_rate)
362{
Tomasz Figa52b06012013-08-26 19:09:04 +0200363 struct samsung_clk_pll *pll = to_clk_pll(hw);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900364 u32 mdiv, pdiv, sdiv, pll_con;
365 u64 fvco = parent_rate;
366
367 pll_con = __raw_readl(pll->con_reg);
368 mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
369 pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
370 sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
371
372 if (pll->type == pll_4508)
373 sdiv = sdiv - 1;
374
375 fvco *= mdiv;
376 do_div(fvco, (pdiv << sdiv));
377
378 return (unsigned long)fvco;
379}
380
Tomasz Figab4054ac2013-08-26 19:09:05 +0200381static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
382 const struct samsung_pll_rate_table *rate)
383{
384 u32 old_mdiv, old_pdiv, old_afc;
385
386 old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
387 old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
388 old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK;
389
390 return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
391 || old_afc != rate->afc);
392}
393
394static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
395 unsigned long prate)
396{
397 struct samsung_clk_pll *pll = to_clk_pll(hw);
398 const struct samsung_pll_rate_table *rate;
399 u32 con0, con1;
400 ktime_t start;
401
402 /* Get required rate settings from table */
403 rate = samsung_get_pll_settings(pll, drate);
404 if (!rate) {
405 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
406 drate, __clk_get_name(hw->clk));
407 return -EINVAL;
408 }
409
410 con0 = __raw_readl(pll->con_reg);
411 con1 = __raw_readl(pll->con_reg + 0x4);
412
413 if (!(samsung_pll45xx_mp_change(con0, con1, rate))) {
414 /* If only s change, change just s value only*/
415 con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT);
416 con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT;
417 __raw_writel(con0, pll->con_reg);
418
419 return 0;
420 }
421
422 /* Set PLL PMS values. */
423 con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) |
424 (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) |
425 (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT));
426 con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) |
427 (rate->pdiv << PLL45XX_PDIV_SHIFT) |
428 (rate->sdiv << PLL45XX_SDIV_SHIFT);
429
430 /* Set PLL AFC value. */
431 con1 = __raw_readl(pll->con_reg + 0x4);
432 con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT);
433 con1 |= (rate->afc << PLL45XX_AFC_SHIFT);
434
435 /* Set PLL lock time. */
436 switch (pll->type) {
437 case pll_4502:
438 __raw_writel(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg);
439 break;
440 case pll_4508:
441 __raw_writel(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg);
442 break;
443 default:
444 break;
Sachin Kamat8e31d192014-01-17 17:05:52 +0530445 }
Tomasz Figab4054ac2013-08-26 19:09:05 +0200446
447 /* Set new configuration. */
448 __raw_writel(con1, pll->con_reg + 0x4);
449 __raw_writel(con0, pll->con_reg);
450
451 /* Wait for locking. */
452 start = ktime_get();
453 while (!(__raw_readl(pll->con_reg) & PLL45XX_LOCKED)) {
454 ktime_t delta = ktime_sub(ktime_get(), start);
455
456 if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
457 pr_err("%s: could not lock PLL %s\n",
458 __func__, __clk_get_name(hw->clk));
459 return -EFAULT;
460 }
461
462 cpu_relax();
463 }
464
465 return 0;
466}
467
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900468static const struct clk_ops samsung_pll45xx_clk_ops = {
469 .recalc_rate = samsung_pll45xx_recalc_rate,
Tomasz Figab4054ac2013-08-26 19:09:05 +0200470 .round_rate = samsung_pll_round_rate,
471 .set_rate = samsung_pll45xx_set_rate,
472};
473
474static const struct clk_ops samsung_pll45xx_clk_min_ops = {
475 .recalc_rate = samsung_pll45xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900476};
477
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900478/*
479 * PLL46xx Clock Type
480 */
Tomasz Figa5c896582013-08-26 19:09:07 +0200481#define PLL46XX_LOCK_FACTOR 3000
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900482
Tomasz Figa5c896582013-08-26 19:09:07 +0200483#define PLL46XX_VSEL_MASK (1)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900484#define PLL46XX_MDIV_MASK (0x1FF)
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530485#define PLL1460X_MDIV_MASK (0x3FF)
486
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900487#define PLL46XX_PDIV_MASK (0x3F)
488#define PLL46XX_SDIV_MASK (0x7)
Tomasz Figa5c896582013-08-26 19:09:07 +0200489#define PLL46XX_VSEL_SHIFT (27)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900490#define PLL46XX_MDIV_SHIFT (16)
491#define PLL46XX_PDIV_SHIFT (8)
492#define PLL46XX_SDIV_SHIFT (0)
493
494#define PLL46XX_KDIV_MASK (0xFFFF)
495#define PLL4650C_KDIV_MASK (0xFFF)
496#define PLL46XX_KDIV_SHIFT (0)
Tomasz Figa5c896582013-08-26 19:09:07 +0200497#define PLL46XX_MFR_MASK (0x3F)
498#define PLL46XX_MRR_MASK (0x1F)
499#define PLL46XX_KDIV_SHIFT (0)
500#define PLL46XX_MFR_SHIFT (16)
501#define PLL46XX_MRR_SHIFT (24)
502
503#define PLL46XX_ENABLE BIT(31)
504#define PLL46XX_LOCKED BIT(29)
505#define PLL46XX_VSEL BIT(27)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900506
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900507static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
508 unsigned long parent_rate)
509{
Tomasz Figac50d11f2013-08-26 19:09:06 +0200510 struct samsung_clk_pll *pll = to_clk_pll(hw);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900511 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
512 u64 fvco = parent_rate;
513
514 pll_con0 = __raw_readl(pll->con_reg);
515 pll_con1 = __raw_readl(pll->con_reg + 4);
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530516 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & ((pll->type == pll_1460x) ?
517 PLL1460X_MDIV_MASK : PLL46XX_MDIV_MASK);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900518 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
519 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
520 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
521 pll_con1 & PLL46XX_KDIV_MASK;
522
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530523 shift = ((pll->type == pll_4600) || (pll->type == pll_1460x)) ? 16 : 10;
524
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900525 fvco *= (mdiv << shift) + kdiv;
526 do_div(fvco, (pdiv << sdiv));
527 fvco >>= shift;
528
529 return (unsigned long)fvco;
530}
531
Tomasz Figa5c896582013-08-26 19:09:07 +0200532static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
533 const struct samsung_pll_rate_table *rate)
534{
535 u32 old_mdiv, old_pdiv, old_kdiv;
536
537 old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
538 old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
539 old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
540
541 return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
542 || old_kdiv != rate->kdiv);
543}
544
545static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
546 unsigned long prate)
547{
548 struct samsung_clk_pll *pll = to_clk_pll(hw);
549 const struct samsung_pll_rate_table *rate;
550 u32 con0, con1, lock;
551 ktime_t start;
552
553 /* Get required rate settings from table */
554 rate = samsung_get_pll_settings(pll, drate);
555 if (!rate) {
556 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
557 drate, __clk_get_name(hw->clk));
558 return -EINVAL;
559 }
560
561 con0 = __raw_readl(pll->con_reg);
562 con1 = __raw_readl(pll->con_reg + 0x4);
563
564 if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
565 /* If only s change, change just s value only*/
566 con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
567 con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
568 __raw_writel(con0, pll->con_reg);
569
570 return 0;
571 }
572
573 /* Set PLL lock time. */
574 lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
575 if (lock > 0xffff)
576 /* Maximum lock time bitfield is 16-bit. */
577 lock = 0xffff;
578
579 /* Set PLL PMS and VSEL values. */
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530580 if (pll->type == pll_1460x) {
581 con0 &= ~((PLL1460X_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
582 (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
583 (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT));
584 } else {
585 con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
Tomasz Figa5c896582013-08-26 19:09:07 +0200586 (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
587 (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
588 (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530589 con0 |= rate->vsel << PLL46XX_VSEL_SHIFT;
590 }
591
Tomasz Figa5c896582013-08-26 19:09:07 +0200592 con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
593 (rate->pdiv << PLL46XX_PDIV_SHIFT) |
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +0530594 (rate->sdiv << PLL46XX_SDIV_SHIFT);
Tomasz Figa5c896582013-08-26 19:09:07 +0200595
596 /* Set PLL K, MFR and MRR values. */
597 con1 = __raw_readl(pll->con_reg + 0x4);
598 con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
599 (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
600 (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
601 con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
602 (rate->mfr << PLL46XX_MFR_SHIFT) |
603 (rate->mrr << PLL46XX_MRR_SHIFT);
604
605 /* Write configuration to PLL */
606 __raw_writel(lock, pll->lock_reg);
607 __raw_writel(con0, pll->con_reg);
608 __raw_writel(con1, pll->con_reg + 0x4);
609
610 /* Wait for locking. */
611 start = ktime_get();
612 while (!(__raw_readl(pll->con_reg) & PLL46XX_LOCKED)) {
613 ktime_t delta = ktime_sub(ktime_get(), start);
614
615 if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
616 pr_err("%s: could not lock PLL %s\n",
617 __func__, __clk_get_name(hw->clk));
618 return -EFAULT;
619 }
620
621 cpu_relax();
622 }
623
624 return 0;
625}
626
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900627static const struct clk_ops samsung_pll46xx_clk_ops = {
628 .recalc_rate = samsung_pll46xx_recalc_rate,
Tomasz Figa5c896582013-08-26 19:09:07 +0200629 .round_rate = samsung_pll_round_rate,
630 .set_rate = samsung_pll46xx_set_rate,
631};
632
633static const struct clk_ops samsung_pll46xx_clk_min_ops = {
634 .recalc_rate = samsung_pll46xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900635};
636
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900637/*
Tomasz Figaeb527122013-07-23 01:49:19 +0200638 * PLL6552 Clock Type
639 */
640
Tomasz Figaeb527122013-07-23 01:49:19 +0200641#define PLL6552_MDIV_MASK 0x3ff
642#define PLL6552_PDIV_MASK 0x3f
643#define PLL6552_SDIV_MASK 0x7
644#define PLL6552_MDIV_SHIFT 16
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900645#define PLL6552_MDIV_SHIFT_2416 14
Tomasz Figaeb527122013-07-23 01:49:19 +0200646#define PLL6552_PDIV_SHIFT 8
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900647#define PLL6552_PDIV_SHIFT_2416 5
Tomasz Figaeb527122013-07-23 01:49:19 +0200648#define PLL6552_SDIV_SHIFT 0
649
Tomasz Figaeb527122013-07-23 01:49:19 +0200650static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
651 unsigned long parent_rate)
652{
Tomasz Figa40ef7232013-08-21 02:33:21 +0200653 struct samsung_clk_pll *pll = to_clk_pll(hw);
Tomasz Figaeb527122013-07-23 01:49:19 +0200654 u32 mdiv, pdiv, sdiv, pll_con;
655 u64 fvco = parent_rate;
656
Tomasz Figa40ef7232013-08-21 02:33:21 +0200657 pll_con = __raw_readl(pll->con_reg);
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900658 if (pll->type == pll_6552_s3c2416) {
659 mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
660 pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
661 } else {
662 mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
663 pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
664 }
Tomasz Figaeb527122013-07-23 01:49:19 +0200665 sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
666
667 fvco *= mdiv;
668 do_div(fvco, (pdiv << sdiv));
669
670 return (unsigned long)fvco;
671}
672
673static const struct clk_ops samsung_pll6552_clk_ops = {
674 .recalc_rate = samsung_pll6552_recalc_rate,
675};
676
Tomasz Figaeb527122013-07-23 01:49:19 +0200677/*
678 * PLL6553 Clock Type
679 */
680
Tomasz Figaeb527122013-07-23 01:49:19 +0200681#define PLL6553_MDIV_MASK 0xff
682#define PLL6553_PDIV_MASK 0x3f
683#define PLL6553_SDIV_MASK 0x7
684#define PLL6553_KDIV_MASK 0xffff
685#define PLL6553_MDIV_SHIFT 16
686#define PLL6553_PDIV_SHIFT 8
687#define PLL6553_SDIV_SHIFT 0
688#define PLL6553_KDIV_SHIFT 0
689
Tomasz Figaeb527122013-07-23 01:49:19 +0200690static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
691 unsigned long parent_rate)
692{
Tomasz Figa40ef7232013-08-21 02:33:21 +0200693 struct samsung_clk_pll *pll = to_clk_pll(hw);
Tomasz Figaeb527122013-07-23 01:49:19 +0200694 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
695 u64 fvco = parent_rate;
696
Tomasz Figa40ef7232013-08-21 02:33:21 +0200697 pll_con0 = __raw_readl(pll->con_reg);
698 pll_con1 = __raw_readl(pll->con_reg + 0x4);
Tomasz Figaeb527122013-07-23 01:49:19 +0200699 mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
700 pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
701 sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
702 kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
703
704 fvco *= (mdiv << 16) + kdiv;
705 do_div(fvco, (pdiv << sdiv));
706 fvco >>= 16;
707
708 return (unsigned long)fvco;
709}
710
711static const struct clk_ops samsung_pll6553_clk_ops = {
712 .recalc_rate = samsung_pll6553_recalc_rate,
713};
714
Tomasz Figaeb527122013-07-23 01:49:19 +0200715/*
Heiko Stuebnerea5d6a82014-02-25 09:50:43 +0900716 * PLL Clock Type of S3C24XX before S3C2443
717 */
718
719#define PLLS3C2410_MDIV_MASK (0xff)
720#define PLLS3C2410_PDIV_MASK (0x1f)
721#define PLLS3C2410_SDIV_MASK (0x3)
722#define PLLS3C2410_MDIV_SHIFT (12)
723#define PLLS3C2410_PDIV_SHIFT (4)
724#define PLLS3C2410_SDIV_SHIFT (0)
725
726#define PLLS3C2410_ENABLE_REG_OFFSET 0x10
727
728static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
729 unsigned long parent_rate)
730{
731 struct samsung_clk_pll *pll = to_clk_pll(hw);
732 u32 pll_con, mdiv, pdiv, sdiv;
733 u64 fvco = parent_rate;
734
735 pll_con = __raw_readl(pll->con_reg);
736 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
737 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
738 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
739
740 fvco *= (mdiv + 8);
741 do_div(fvco, (pdiv + 2) << sdiv);
742
743 return (unsigned int)fvco;
744}
745
746static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
747 unsigned long parent_rate)
748{
749 struct samsung_clk_pll *pll = to_clk_pll(hw);
750 u32 pll_con, mdiv, pdiv, sdiv;
751 u64 fvco = parent_rate;
752
753 pll_con = __raw_readl(pll->con_reg);
754 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
755 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
756 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
757
758 fvco *= (2 * (mdiv + 8));
759 do_div(fvco, (pdiv + 2) << sdiv);
760
761 return (unsigned int)fvco;
762}
763
764static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
765 unsigned long prate)
766{
767 struct samsung_clk_pll *pll = to_clk_pll(hw);
768 const struct samsung_pll_rate_table *rate;
769 u32 tmp;
770
771 /* Get required rate settings from table */
772 rate = samsung_get_pll_settings(pll, drate);
773 if (!rate) {
774 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
775 drate, __clk_get_name(hw->clk));
776 return -EINVAL;
777 }
778
779 tmp = __raw_readl(pll->con_reg);
780
781 /* Change PLL PMS values */
782 tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
783 (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
784 (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
785 tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
786 (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
787 (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
788 __raw_writel(tmp, pll->con_reg);
789
790 /* Time to settle according to the manual */
791 udelay(300);
792
793 return 0;
794}
795
796static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
797{
798 struct samsung_clk_pll *pll = to_clk_pll(hw);
799 u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
800 u32 pll_en_orig = pll_en;
801
802 if (enable)
803 pll_en &= ~BIT(bit);
804 else
805 pll_en |= BIT(bit);
806
807 __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
808
809 /* if we started the UPLL, then allow to settle */
810 if (enable && (pll_en_orig & BIT(bit)))
811 udelay(300);
812
813 return 0;
814}
815
816static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
817{
818 return samsung_s3c2410_pll_enable(hw, 5, true);
819}
820
821static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
822{
823 samsung_s3c2410_pll_enable(hw, 5, false);
824}
825
826static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
827{
828 return samsung_s3c2410_pll_enable(hw, 7, true);
829}
830
831static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
832{
833 samsung_s3c2410_pll_enable(hw, 7, false);
834}
835
836static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
837 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
838 .enable = samsung_s3c2410_mpll_enable,
839 .disable = samsung_s3c2410_mpll_disable,
840};
841
842static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
843 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
844 .enable = samsung_s3c2410_upll_enable,
845 .disable = samsung_s3c2410_upll_disable,
846};
847
848static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
849 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
850 .enable = samsung_s3c2410_mpll_enable,
851 .disable = samsung_s3c2410_mpll_disable,
852};
853
854static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
855 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
856 .enable = samsung_s3c2410_mpll_enable,
857 .disable = samsung_s3c2410_mpll_disable,
858 .round_rate = samsung_pll_round_rate,
859 .set_rate = samsung_s3c2410_pll_set_rate,
860};
861
862static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
863 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
864 .enable = samsung_s3c2410_upll_enable,
865 .disable = samsung_s3c2410_upll_disable,
866 .round_rate = samsung_pll_round_rate,
867 .set_rate = samsung_s3c2410_pll_set_rate,
868};
869
870static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
871 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
872 .enable = samsung_s3c2410_mpll_enable,
873 .disable = samsung_s3c2410_mpll_disable,
874 .round_rate = samsung_pll_round_rate,
875 .set_rate = samsung_s3c2410_pll_set_rate,
876};
877
878/*
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900879 * PLL2550x Clock Type
880 */
881
882#define PLL2550X_R_MASK (0x1)
883#define PLL2550X_P_MASK (0x3F)
884#define PLL2550X_M_MASK (0x3FF)
885#define PLL2550X_S_MASK (0x7)
886#define PLL2550X_R_SHIFT (20)
887#define PLL2550X_P_SHIFT (14)
888#define PLL2550X_M_SHIFT (4)
889#define PLL2550X_S_SHIFT (0)
890
891struct samsung_clk_pll2550x {
892 struct clk_hw hw;
893 const void __iomem *reg_base;
894 unsigned long offset;
895};
896
897#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
898
899static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
900 unsigned long parent_rate)
901{
902 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
903 u32 r, p, m, s, pll_stat;
904 u64 fvco = parent_rate;
905
906 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
907 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
908 if (!r)
909 return 0;
910 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
911 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
912 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
913
914 fvco *= m;
915 do_div(fvco, (p << s));
916
917 return (unsigned long)fvco;
918}
919
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900920static const struct clk_ops samsung_pll2550x_clk_ops = {
921 .recalc_rate = samsung_pll2550x_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900922};
923
924struct clk * __init samsung_clk_register_pll2550x(const char *name,
925 const char *pname, const void __iomem *reg_base,
926 const unsigned long offset)
927{
928 struct samsung_clk_pll2550x *pll;
929 struct clk *clk;
930 struct clk_init_data init;
931
932 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
933 if (!pll) {
934 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
935 return NULL;
936 }
937
938 init.name = name;
939 init.ops = &samsung_pll2550x_clk_ops;
940 init.flags = CLK_GET_RATE_NOCACHE;
941 init.parent_names = &pname;
942 init.num_parents = 1;
943
944 pll->hw.init = &init;
945 pll->reg_base = reg_base;
946 pll->offset = offset;
947
948 clk = clk_register(NULL, &pll->hw);
949 if (IS_ERR(clk)) {
950 pr_err("%s: failed to register pll clock %s\n", __func__,
951 name);
952 kfree(pll);
953 }
954
955 if (clk_register_clkdev(clk, name, NULL))
956 pr_err("%s: failed to register lookup for %s", __func__, name);
957
958 return clk;
959}
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530960
Pankaj Dubey84329842014-03-12 20:26:45 +0530961/*
962 * PLL2550xx Clock Type
963 */
964
965/* Maximum lock time can be 270 * PDIV cycles */
966#define PLL2550XX_LOCK_FACTOR 270
967
968#define PLL2550XX_M_MASK 0x3FF
969#define PLL2550XX_P_MASK 0x3F
970#define PLL2550XX_S_MASK 0x7
971#define PLL2550XX_LOCK_STAT_MASK 0x1
972#define PLL2550XX_M_SHIFT 9
973#define PLL2550XX_P_SHIFT 3
974#define PLL2550XX_S_SHIFT 0
975#define PLL2550XX_LOCK_STAT_SHIFT 21
976
977static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
978 unsigned long parent_rate)
979{
980 struct samsung_clk_pll *pll = to_clk_pll(hw);
981 u32 mdiv, pdiv, sdiv, pll_con;
982 u64 fvco = parent_rate;
983
984 pll_con = __raw_readl(pll->con_reg);
985 mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
986 pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
987 sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
988
989 fvco *= mdiv;
990 do_div(fvco, (pdiv << sdiv));
991
992 return (unsigned long)fvco;
993}
994
995static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
996{
997 u32 old_mdiv, old_pdiv;
998
999 old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
1000 old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
1001
1002 return mdiv != old_mdiv || pdiv != old_pdiv;
1003}
1004
1005static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
1006 unsigned long prate)
1007{
1008 struct samsung_clk_pll *pll = to_clk_pll(hw);
1009 const struct samsung_pll_rate_table *rate;
1010 u32 tmp;
1011
1012 /* Get required rate settings from table */
1013 rate = samsung_get_pll_settings(pll, drate);
1014 if (!rate) {
1015 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1016 drate, __clk_get_name(hw->clk));
1017 return -EINVAL;
1018 }
1019
1020 tmp = __raw_readl(pll->con_reg);
1021
1022 if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1023 /* If only s change, change just s value only*/
1024 tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1025 tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1026 __raw_writel(tmp, pll->con_reg);
1027
1028 return 0;
1029 }
1030
1031 /* Set PLL lock time. */
1032 __raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1033
1034 /* Change PLL PMS values */
1035 tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1036 (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1037 (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1038 tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1039 (rate->pdiv << PLL2550XX_P_SHIFT) |
1040 (rate->sdiv << PLL2550XX_S_SHIFT);
1041 __raw_writel(tmp, pll->con_reg);
1042
1043 /* wait_lock_time */
1044 do {
1045 cpu_relax();
1046 tmp = __raw_readl(pll->con_reg);
1047 } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1048 << PLL2550XX_LOCK_STAT_SHIFT)));
1049
1050 return 0;
1051}
1052
1053static const struct clk_ops samsung_pll2550xx_clk_ops = {
1054 .recalc_rate = samsung_pll2550xx_recalc_rate,
1055 .round_rate = samsung_pll_round_rate,
1056 .set_rate = samsung_pll2550xx_set_rate,
1057};
1058
1059static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1060 .recalc_rate = samsung_pll2550xx_recalc_rate,
1061};
1062
Rahul Sharmaeefe1192014-03-12 20:26:46 +05301063/*
1064 * PLL2650XX Clock Type
1065 */
1066
1067/* Maximum lock time can be 3000 * PDIV cycles */
1068#define PLL2650XX_LOCK_FACTOR 3000
1069
1070#define PLL2650XX_MDIV_SHIFT 9
1071#define PLL2650XX_PDIV_SHIFT 3
1072#define PLL2650XX_SDIV_SHIFT 0
1073#define PLL2650XX_KDIV_SHIFT 0
1074#define PLL2650XX_MDIV_MASK 0x1ff
1075#define PLL2650XX_PDIV_MASK 0x3f
1076#define PLL2650XX_SDIV_MASK 0x7
1077#define PLL2650XX_KDIV_MASK 0xffff
1078#define PLL2650XX_PLL_ENABLE_SHIFT 23
1079#define PLL2650XX_PLL_LOCKTIME_SHIFT 21
1080#define PLL2650XX_PLL_FOUTMASK_SHIFT 31
1081
1082static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1083 unsigned long parent_rate)
1084{
1085 struct samsung_clk_pll *pll = to_clk_pll(hw);
1086 u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1087 s16 kdiv;
1088 u64 fvco = parent_rate;
1089
1090 pll_con0 = __raw_readl(pll->con_reg);
1091 pll_con2 = __raw_readl(pll->con_reg + 8);
1092 mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1093 pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1094 sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1095 kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1096
1097 fvco *= (mdiv << 16) + kdiv;
1098 do_div(fvco, (pdiv << sdiv));
1099 fvco >>= 16;
1100
1101 return (unsigned long)fvco;
1102}
1103
1104static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1105 unsigned long parent_rate)
1106{
1107 struct samsung_clk_pll *pll = to_clk_pll(hw);
1108 u32 tmp, pll_con0, pll_con2;
1109 const struct samsung_pll_rate_table *rate;
1110
1111 rate = samsung_get_pll_settings(pll, drate);
1112 if (!rate) {
1113 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1114 drate, __clk_get_name(hw->clk));
1115 return -EINVAL;
1116 }
1117
1118 pll_con0 = __raw_readl(pll->con_reg);
1119 pll_con2 = __raw_readl(pll->con_reg + 8);
1120
1121 /* Change PLL PMS values */
1122 pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1123 PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1124 PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1125 pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1126 pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1127 pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1128 pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1129 pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1130
1131 pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1132 pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1133 << PLL2650XX_KDIV_SHIFT;
1134
1135 /* Set PLL lock time. */
1136 __raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1137
1138 __raw_writel(pll_con0, pll->con_reg);
1139 __raw_writel(pll_con2, pll->con_reg + 8);
1140
1141 do {
1142 tmp = __raw_readl(pll->con_reg);
1143 } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1144
1145 return 0;
1146}
1147
1148static const struct clk_ops samsung_pll2650xx_clk_ops = {
1149 .recalc_rate = samsung_pll2650xx_recalc_rate,
1150 .set_rate = samsung_pll2650xx_set_rate,
1151 .round_rate = samsung_pll_round_rate,
1152};
1153
1154static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1155 .recalc_rate = samsung_pll2650xx_recalc_rate,
1156};
1157
Rahul Sharma976face2014-03-12 20:26:44 +05301158static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
Uwe Kleine-König4a1caed2015-05-28 10:45:51 +02001159 const struct samsung_pll_clock *pll_clk,
Rahul Sharma976face2014-03-12 20:26:44 +05301160 void __iomem *base)
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301161{
1162 struct samsung_clk_pll *pll;
1163 struct clk *clk;
1164 struct clk_init_data init;
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +05301165 int ret, len;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301166
1167 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
1168 if (!pll) {
1169 pr_err("%s: could not allocate pll clk %s\n",
1170 __func__, pll_clk->name);
1171 return;
1172 }
1173
1174 init.name = pll_clk->name;
1175 init.flags = pll_clk->flags;
1176 init.parent_names = &pll_clk->parent_name;
1177 init.num_parents = 1;
1178
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +05301179 if (pll_clk->rate_table) {
1180 /* find count of rates in rate_table */
1181 for (len = 0; pll_clk->rate_table[len].rate != 0; )
1182 len++;
1183
1184 pll->rate_count = len;
1185 pll->rate_table = kmemdup(pll_clk->rate_table,
1186 pll->rate_count *
1187 sizeof(struct samsung_pll_rate_table),
1188 GFP_KERNEL);
1189 WARN(!pll->rate_table,
1190 "%s: could not allocate rate table for %s\n",
1191 __func__, pll_clk->name);
1192 }
1193
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301194 switch (pll_clk->type) {
Heiko Stuebnera951b1d2014-02-19 09:25:41 +09001195 case pll_2126:
1196 init.ops = &samsung_pll2126_clk_ops;
1197 break;
1198 case pll_3000:
1199 init.ops = &samsung_pll3000_clk_ops;
1200 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301201 /* clk_ops for 35xx and 2550 are similar */
1202 case pll_35xx:
1203 case pll_2550:
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +05301204 case pll_1450x:
1205 case pll_1451x:
1206 case pll_1452x:
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +05301207 if (!pll->rate_table)
1208 init.ops = &samsung_pll35xx_clk_min_ops;
1209 else
1210 init.ops = &samsung_pll35xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301211 break;
Tomasz Figa52b06012013-08-26 19:09:04 +02001212 case pll_4500:
Tomasz Figab4054ac2013-08-26 19:09:05 +02001213 init.ops = &samsung_pll45xx_clk_min_ops;
1214 break;
Tomasz Figa52b06012013-08-26 19:09:04 +02001215 case pll_4502:
1216 case pll_4508:
Tomasz Figab4054ac2013-08-26 19:09:05 +02001217 if (!pll->rate_table)
1218 init.ops = &samsung_pll45xx_clk_min_ops;
1219 else
1220 init.ops = &samsung_pll45xx_clk_ops;
Tomasz Figa52b06012013-08-26 19:09:04 +02001221 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301222 /* clk_ops for 36xx and 2650 are similar */
1223 case pll_36xx:
1224 case pll_2650:
Vikas Sajjanbb4278d2013-06-11 15:01:14 +05301225 if (!pll->rate_table)
1226 init.ops = &samsung_pll36xx_clk_min_ops;
1227 else
1228 init.ops = &samsung_pll36xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301229 break;
Tomasz Figa40ef7232013-08-21 02:33:21 +02001230 case pll_6552:
Heiko Stuebner06654ac2014-02-19 09:25:36 +09001231 case pll_6552_s3c2416:
Tomasz Figa40ef7232013-08-21 02:33:21 +02001232 init.ops = &samsung_pll6552_clk_ops;
1233 break;
1234 case pll_6553:
1235 init.ops = &samsung_pll6553_clk_ops;
1236 break;
Tomasz Figac50d11f2013-08-26 19:09:06 +02001237 case pll_4600:
1238 case pll_4650:
1239 case pll_4650c:
Naveen Krishna Ch0c23e2a2014-09-22 10:17:01 +05301240 case pll_1460x:
Tomasz Figa5c896582013-08-26 19:09:07 +02001241 if (!pll->rate_table)
1242 init.ops = &samsung_pll46xx_clk_min_ops;
1243 else
1244 init.ops = &samsung_pll46xx_clk_ops;
Tomasz Figac50d11f2013-08-26 19:09:06 +02001245 break;
Heiko Stuebnerea5d6a82014-02-25 09:50:43 +09001246 case pll_s3c2410_mpll:
1247 if (!pll->rate_table)
1248 init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1249 else
1250 init.ops = &samsung_s3c2410_mpll_clk_ops;
1251 break;
1252 case pll_s3c2410_upll:
1253 if (!pll->rate_table)
1254 init.ops = &samsung_s3c2410_upll_clk_min_ops;
1255 else
1256 init.ops = &samsung_s3c2410_upll_clk_ops;
1257 break;
1258 case pll_s3c2440_mpll:
1259 if (!pll->rate_table)
1260 init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1261 else
1262 init.ops = &samsung_s3c2440_mpll_clk_ops;
1263 break;
Pankaj Dubey84329842014-03-12 20:26:45 +05301264 case pll_2550xx:
1265 if (!pll->rate_table)
1266 init.ops = &samsung_pll2550xx_clk_min_ops;
1267 else
1268 init.ops = &samsung_pll2550xx_clk_ops;
1269 break;
Rahul Sharmaeefe1192014-03-12 20:26:46 +05301270 case pll_2650xx:
1271 if (!pll->rate_table)
1272 init.ops = &samsung_pll2650xx_clk_min_ops;
1273 else
1274 init.ops = &samsung_pll2650xx_clk_ops;
1275 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301276 default:
1277 pr_warn("%s: Unknown pll type for pll clk %s\n",
1278 __func__, pll_clk->name);
1279 }
1280
1281 pll->hw.init = &init;
1282 pll->type = pll_clk->type;
1283 pll->lock_reg = base + pll_clk->lock_offset;
1284 pll->con_reg = base + pll_clk->con_offset;
1285
1286 clk = clk_register(NULL, &pll->hw);
1287 if (IS_ERR(clk)) {
1288 pr_err("%s: failed to register pll clock %s : %ld\n",
1289 __func__, pll_clk->name, PTR_ERR(clk));
1290 kfree(pll);
1291 return;
1292 }
1293
Rahul Sharma976face2014-03-12 20:26:44 +05301294 samsung_clk_add_lookup(ctx, clk, pll_clk->id);
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301295
1296 if (!pll_clk->alias)
1297 return;
1298
1299 ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
1300 if (ret)
1301 pr_err("%s: failed to register lookup for %s : %d",
1302 __func__, pll_clk->name, ret);
1303}
1304
Rahul Sharma976face2014-03-12 20:26:44 +05301305void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
Uwe Kleine-König4a1caed2015-05-28 10:45:51 +02001306 const struct samsung_pll_clock *pll_list,
Rahul Sharma976face2014-03-12 20:26:44 +05301307 unsigned int nr_pll, void __iomem *base)
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301308{
1309 int cnt;
1310
1311 for (cnt = 0; cnt < nr_pll; cnt++)
Rahul Sharma976face2014-03-12 20:26:44 +05301312 _samsung_clk_register_pll(ctx, &pll_list[cnt], base);
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301313}