blob: b07fad2a916703731731f40b5db3aa678e835b17 [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)
485#define PLL46XX_PDIV_MASK (0x3F)
486#define PLL46XX_SDIV_MASK (0x7)
Tomasz Figa5c896582013-08-26 19:09:07 +0200487#define PLL46XX_VSEL_SHIFT (27)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900488#define PLL46XX_MDIV_SHIFT (16)
489#define PLL46XX_PDIV_SHIFT (8)
490#define PLL46XX_SDIV_SHIFT (0)
491
492#define PLL46XX_KDIV_MASK (0xFFFF)
493#define PLL4650C_KDIV_MASK (0xFFF)
494#define PLL46XX_KDIV_SHIFT (0)
Tomasz Figa5c896582013-08-26 19:09:07 +0200495#define PLL46XX_MFR_MASK (0x3F)
496#define PLL46XX_MRR_MASK (0x1F)
497#define PLL46XX_KDIV_SHIFT (0)
498#define PLL46XX_MFR_SHIFT (16)
499#define PLL46XX_MRR_SHIFT (24)
500
501#define PLL46XX_ENABLE BIT(31)
502#define PLL46XX_LOCKED BIT(29)
503#define PLL46XX_VSEL BIT(27)
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900504
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900505static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
506 unsigned long parent_rate)
507{
Tomasz Figac50d11f2013-08-26 19:09:06 +0200508 struct samsung_clk_pll *pll = to_clk_pll(hw);
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900509 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
510 u64 fvco = parent_rate;
511
512 pll_con0 = __raw_readl(pll->con_reg);
513 pll_con1 = __raw_readl(pll->con_reg + 4);
514 mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
515 pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
516 sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
517 kdiv = pll->type == pll_4650c ? pll_con1 & PLL4650C_KDIV_MASK :
518 pll_con1 & PLL46XX_KDIV_MASK;
519
520 shift = pll->type == pll_4600 ? 16 : 10;
521 fvco *= (mdiv << shift) + kdiv;
522 do_div(fvco, (pdiv << sdiv));
523 fvco >>= shift;
524
525 return (unsigned long)fvco;
526}
527
Tomasz Figa5c896582013-08-26 19:09:07 +0200528static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
529 const struct samsung_pll_rate_table *rate)
530{
531 u32 old_mdiv, old_pdiv, old_kdiv;
532
533 old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
534 old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
535 old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
536
537 return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
538 || old_kdiv != rate->kdiv);
539}
540
541static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
542 unsigned long prate)
543{
544 struct samsung_clk_pll *pll = to_clk_pll(hw);
545 const struct samsung_pll_rate_table *rate;
546 u32 con0, con1, lock;
547 ktime_t start;
548
549 /* Get required rate settings from table */
550 rate = samsung_get_pll_settings(pll, drate);
551 if (!rate) {
552 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
553 drate, __clk_get_name(hw->clk));
554 return -EINVAL;
555 }
556
557 con0 = __raw_readl(pll->con_reg);
558 con1 = __raw_readl(pll->con_reg + 0x4);
559
560 if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
561 /* If only s change, change just s value only*/
562 con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
563 con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
564 __raw_writel(con0, pll->con_reg);
565
566 return 0;
567 }
568
569 /* Set PLL lock time. */
570 lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
571 if (lock > 0xffff)
572 /* Maximum lock time bitfield is 16-bit. */
573 lock = 0xffff;
574
575 /* Set PLL PMS and VSEL values. */
576 con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
577 (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
578 (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
579 (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
580 con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
581 (rate->pdiv << PLL46XX_PDIV_SHIFT) |
582 (rate->sdiv << PLL46XX_SDIV_SHIFT) |
583 (rate->vsel << PLL46XX_VSEL_SHIFT);
584
585 /* Set PLL K, MFR and MRR values. */
586 con1 = __raw_readl(pll->con_reg + 0x4);
587 con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
588 (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
589 (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
590 con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
591 (rate->mfr << PLL46XX_MFR_SHIFT) |
592 (rate->mrr << PLL46XX_MRR_SHIFT);
593
594 /* Write configuration to PLL */
595 __raw_writel(lock, pll->lock_reg);
596 __raw_writel(con0, pll->con_reg);
597 __raw_writel(con1, pll->con_reg + 0x4);
598
599 /* Wait for locking. */
600 start = ktime_get();
601 while (!(__raw_readl(pll->con_reg) & PLL46XX_LOCKED)) {
602 ktime_t delta = ktime_sub(ktime_get(), start);
603
604 if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
605 pr_err("%s: could not lock PLL %s\n",
606 __func__, __clk_get_name(hw->clk));
607 return -EFAULT;
608 }
609
610 cpu_relax();
611 }
612
613 return 0;
614}
615
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900616static const struct clk_ops samsung_pll46xx_clk_ops = {
617 .recalc_rate = samsung_pll46xx_recalc_rate,
Tomasz Figa5c896582013-08-26 19:09:07 +0200618 .round_rate = samsung_pll_round_rate,
619 .set_rate = samsung_pll46xx_set_rate,
620};
621
622static const struct clk_ops samsung_pll46xx_clk_min_ops = {
623 .recalc_rate = samsung_pll46xx_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900624};
625
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900626/*
Tomasz Figaeb527122013-07-23 01:49:19 +0200627 * PLL6552 Clock Type
628 */
629
Tomasz Figaeb527122013-07-23 01:49:19 +0200630#define PLL6552_MDIV_MASK 0x3ff
631#define PLL6552_PDIV_MASK 0x3f
632#define PLL6552_SDIV_MASK 0x7
633#define PLL6552_MDIV_SHIFT 16
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900634#define PLL6552_MDIV_SHIFT_2416 14
Tomasz Figaeb527122013-07-23 01:49:19 +0200635#define PLL6552_PDIV_SHIFT 8
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900636#define PLL6552_PDIV_SHIFT_2416 5
Tomasz Figaeb527122013-07-23 01:49:19 +0200637#define PLL6552_SDIV_SHIFT 0
638
Tomasz Figaeb527122013-07-23 01:49:19 +0200639static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
640 unsigned long parent_rate)
641{
Tomasz Figa40ef7232013-08-21 02:33:21 +0200642 struct samsung_clk_pll *pll = to_clk_pll(hw);
Tomasz Figaeb527122013-07-23 01:49:19 +0200643 u32 mdiv, pdiv, sdiv, pll_con;
644 u64 fvco = parent_rate;
645
Tomasz Figa40ef7232013-08-21 02:33:21 +0200646 pll_con = __raw_readl(pll->con_reg);
Heiko Stuebner06654ac2014-02-19 09:25:36 +0900647 if (pll->type == pll_6552_s3c2416) {
648 mdiv = (pll_con >> PLL6552_MDIV_SHIFT_2416) & PLL6552_MDIV_MASK;
649 pdiv = (pll_con >> PLL6552_PDIV_SHIFT_2416) & PLL6552_PDIV_MASK;
650 } else {
651 mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
652 pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
653 }
Tomasz Figaeb527122013-07-23 01:49:19 +0200654 sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
655
656 fvco *= mdiv;
657 do_div(fvco, (pdiv << sdiv));
658
659 return (unsigned long)fvco;
660}
661
662static const struct clk_ops samsung_pll6552_clk_ops = {
663 .recalc_rate = samsung_pll6552_recalc_rate,
664};
665
Tomasz Figaeb527122013-07-23 01:49:19 +0200666/*
667 * PLL6553 Clock Type
668 */
669
Tomasz Figaeb527122013-07-23 01:49:19 +0200670#define PLL6553_MDIV_MASK 0xff
671#define PLL6553_PDIV_MASK 0x3f
672#define PLL6553_SDIV_MASK 0x7
673#define PLL6553_KDIV_MASK 0xffff
674#define PLL6553_MDIV_SHIFT 16
675#define PLL6553_PDIV_SHIFT 8
676#define PLL6553_SDIV_SHIFT 0
677#define PLL6553_KDIV_SHIFT 0
678
Tomasz Figaeb527122013-07-23 01:49:19 +0200679static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
680 unsigned long parent_rate)
681{
Tomasz Figa40ef7232013-08-21 02:33:21 +0200682 struct samsung_clk_pll *pll = to_clk_pll(hw);
Tomasz Figaeb527122013-07-23 01:49:19 +0200683 u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
684 u64 fvco = parent_rate;
685
Tomasz Figa40ef7232013-08-21 02:33:21 +0200686 pll_con0 = __raw_readl(pll->con_reg);
687 pll_con1 = __raw_readl(pll->con_reg + 0x4);
Tomasz Figaeb527122013-07-23 01:49:19 +0200688 mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
689 pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
690 sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
691 kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
692
693 fvco *= (mdiv << 16) + kdiv;
694 do_div(fvco, (pdiv << sdiv));
695 fvco >>= 16;
696
697 return (unsigned long)fvco;
698}
699
700static const struct clk_ops samsung_pll6553_clk_ops = {
701 .recalc_rate = samsung_pll6553_recalc_rate,
702};
703
Tomasz Figaeb527122013-07-23 01:49:19 +0200704/*
Heiko Stuebnerea5d6a82014-02-25 09:50:43 +0900705 * PLL Clock Type of S3C24XX before S3C2443
706 */
707
708#define PLLS3C2410_MDIV_MASK (0xff)
709#define PLLS3C2410_PDIV_MASK (0x1f)
710#define PLLS3C2410_SDIV_MASK (0x3)
711#define PLLS3C2410_MDIV_SHIFT (12)
712#define PLLS3C2410_PDIV_SHIFT (4)
713#define PLLS3C2410_SDIV_SHIFT (0)
714
715#define PLLS3C2410_ENABLE_REG_OFFSET 0x10
716
717static unsigned long samsung_s3c2410_pll_recalc_rate(struct clk_hw *hw,
718 unsigned long parent_rate)
719{
720 struct samsung_clk_pll *pll = to_clk_pll(hw);
721 u32 pll_con, mdiv, pdiv, sdiv;
722 u64 fvco = parent_rate;
723
724 pll_con = __raw_readl(pll->con_reg);
725 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
726 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
727 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
728
729 fvco *= (mdiv + 8);
730 do_div(fvco, (pdiv + 2) << sdiv);
731
732 return (unsigned int)fvco;
733}
734
735static unsigned long samsung_s3c2440_mpll_recalc_rate(struct clk_hw *hw,
736 unsigned long parent_rate)
737{
738 struct samsung_clk_pll *pll = to_clk_pll(hw);
739 u32 pll_con, mdiv, pdiv, sdiv;
740 u64 fvco = parent_rate;
741
742 pll_con = __raw_readl(pll->con_reg);
743 mdiv = (pll_con >> PLLS3C2410_MDIV_SHIFT) & PLLS3C2410_MDIV_MASK;
744 pdiv = (pll_con >> PLLS3C2410_PDIV_SHIFT) & PLLS3C2410_PDIV_MASK;
745 sdiv = (pll_con >> PLLS3C2410_SDIV_SHIFT) & PLLS3C2410_SDIV_MASK;
746
747 fvco *= (2 * (mdiv + 8));
748 do_div(fvco, (pdiv + 2) << sdiv);
749
750 return (unsigned int)fvco;
751}
752
753static int samsung_s3c2410_pll_set_rate(struct clk_hw *hw, unsigned long drate,
754 unsigned long prate)
755{
756 struct samsung_clk_pll *pll = to_clk_pll(hw);
757 const struct samsung_pll_rate_table *rate;
758 u32 tmp;
759
760 /* Get required rate settings from table */
761 rate = samsung_get_pll_settings(pll, drate);
762 if (!rate) {
763 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
764 drate, __clk_get_name(hw->clk));
765 return -EINVAL;
766 }
767
768 tmp = __raw_readl(pll->con_reg);
769
770 /* Change PLL PMS values */
771 tmp &= ~((PLLS3C2410_MDIV_MASK << PLLS3C2410_MDIV_SHIFT) |
772 (PLLS3C2410_PDIV_MASK << PLLS3C2410_PDIV_SHIFT) |
773 (PLLS3C2410_SDIV_MASK << PLLS3C2410_SDIV_SHIFT));
774 tmp |= (rate->mdiv << PLLS3C2410_MDIV_SHIFT) |
775 (rate->pdiv << PLLS3C2410_PDIV_SHIFT) |
776 (rate->sdiv << PLLS3C2410_SDIV_SHIFT);
777 __raw_writel(tmp, pll->con_reg);
778
779 /* Time to settle according to the manual */
780 udelay(300);
781
782 return 0;
783}
784
785static int samsung_s3c2410_pll_enable(struct clk_hw *hw, int bit, bool enable)
786{
787 struct samsung_clk_pll *pll = to_clk_pll(hw);
788 u32 pll_en = __raw_readl(pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
789 u32 pll_en_orig = pll_en;
790
791 if (enable)
792 pll_en &= ~BIT(bit);
793 else
794 pll_en |= BIT(bit);
795
796 __raw_writel(pll_en, pll->lock_reg + PLLS3C2410_ENABLE_REG_OFFSET);
797
798 /* if we started the UPLL, then allow to settle */
799 if (enable && (pll_en_orig & BIT(bit)))
800 udelay(300);
801
802 return 0;
803}
804
805static int samsung_s3c2410_mpll_enable(struct clk_hw *hw)
806{
807 return samsung_s3c2410_pll_enable(hw, 5, true);
808}
809
810static void samsung_s3c2410_mpll_disable(struct clk_hw *hw)
811{
812 samsung_s3c2410_pll_enable(hw, 5, false);
813}
814
815static int samsung_s3c2410_upll_enable(struct clk_hw *hw)
816{
817 return samsung_s3c2410_pll_enable(hw, 7, true);
818}
819
820static void samsung_s3c2410_upll_disable(struct clk_hw *hw)
821{
822 samsung_s3c2410_pll_enable(hw, 7, false);
823}
824
825static const struct clk_ops samsung_s3c2410_mpll_clk_min_ops = {
826 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
827 .enable = samsung_s3c2410_mpll_enable,
828 .disable = samsung_s3c2410_mpll_disable,
829};
830
831static const struct clk_ops samsung_s3c2410_upll_clk_min_ops = {
832 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
833 .enable = samsung_s3c2410_upll_enable,
834 .disable = samsung_s3c2410_upll_disable,
835};
836
837static const struct clk_ops samsung_s3c2440_mpll_clk_min_ops = {
838 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
839 .enable = samsung_s3c2410_mpll_enable,
840 .disable = samsung_s3c2410_mpll_disable,
841};
842
843static const struct clk_ops samsung_s3c2410_mpll_clk_ops = {
844 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
845 .enable = samsung_s3c2410_mpll_enable,
846 .disable = samsung_s3c2410_mpll_disable,
847 .round_rate = samsung_pll_round_rate,
848 .set_rate = samsung_s3c2410_pll_set_rate,
849};
850
851static const struct clk_ops samsung_s3c2410_upll_clk_ops = {
852 .recalc_rate = samsung_s3c2410_pll_recalc_rate,
853 .enable = samsung_s3c2410_upll_enable,
854 .disable = samsung_s3c2410_upll_disable,
855 .round_rate = samsung_pll_round_rate,
856 .set_rate = samsung_s3c2410_pll_set_rate,
857};
858
859static const struct clk_ops samsung_s3c2440_mpll_clk_ops = {
860 .recalc_rate = samsung_s3c2440_mpll_recalc_rate,
861 .enable = samsung_s3c2410_mpll_enable,
862 .disable = samsung_s3c2410_mpll_disable,
863 .round_rate = samsung_pll_round_rate,
864 .set_rate = samsung_s3c2410_pll_set_rate,
865};
866
867/*
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900868 * PLL2550x Clock Type
869 */
870
871#define PLL2550X_R_MASK (0x1)
872#define PLL2550X_P_MASK (0x3F)
873#define PLL2550X_M_MASK (0x3FF)
874#define PLL2550X_S_MASK (0x7)
875#define PLL2550X_R_SHIFT (20)
876#define PLL2550X_P_SHIFT (14)
877#define PLL2550X_M_SHIFT (4)
878#define PLL2550X_S_SHIFT (0)
879
880struct samsung_clk_pll2550x {
881 struct clk_hw hw;
882 const void __iomem *reg_base;
883 unsigned long offset;
884};
885
886#define to_clk_pll2550x(_hw) container_of(_hw, struct samsung_clk_pll2550x, hw)
887
888static unsigned long samsung_pll2550x_recalc_rate(struct clk_hw *hw,
889 unsigned long parent_rate)
890{
891 struct samsung_clk_pll2550x *pll = to_clk_pll2550x(hw);
892 u32 r, p, m, s, pll_stat;
893 u64 fvco = parent_rate;
894
895 pll_stat = __raw_readl(pll->reg_base + pll->offset * 3);
896 r = (pll_stat >> PLL2550X_R_SHIFT) & PLL2550X_R_MASK;
897 if (!r)
898 return 0;
899 p = (pll_stat >> PLL2550X_P_SHIFT) & PLL2550X_P_MASK;
900 m = (pll_stat >> PLL2550X_M_SHIFT) & PLL2550X_M_MASK;
901 s = (pll_stat >> PLL2550X_S_SHIFT) & PLL2550X_S_MASK;
902
903 fvco *= m;
904 do_div(fvco, (p << s));
905
906 return (unsigned long)fvco;
907}
908
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900909static const struct clk_ops samsung_pll2550x_clk_ops = {
910 .recalc_rate = samsung_pll2550x_recalc_rate,
Thomas Abraham1c4c5fe2013-03-09 17:02:48 +0900911};
912
913struct clk * __init samsung_clk_register_pll2550x(const char *name,
914 const char *pname, const void __iomem *reg_base,
915 const unsigned long offset)
916{
917 struct samsung_clk_pll2550x *pll;
918 struct clk *clk;
919 struct clk_init_data init;
920
921 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
922 if (!pll) {
923 pr_err("%s: could not allocate pll clk %s\n", __func__, name);
924 return NULL;
925 }
926
927 init.name = name;
928 init.ops = &samsung_pll2550x_clk_ops;
929 init.flags = CLK_GET_RATE_NOCACHE;
930 init.parent_names = &pname;
931 init.num_parents = 1;
932
933 pll->hw.init = &init;
934 pll->reg_base = reg_base;
935 pll->offset = offset;
936
937 clk = clk_register(NULL, &pll->hw);
938 if (IS_ERR(clk)) {
939 pr_err("%s: failed to register pll clock %s\n", __func__,
940 name);
941 kfree(pll);
942 }
943
944 if (clk_register_clkdev(clk, name, NULL))
945 pr_err("%s: failed to register lookup for %s", __func__, name);
946
947 return clk;
948}
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +0530949
Pankaj Dubey84329842014-03-12 20:26:45 +0530950/*
951 * PLL2550xx Clock Type
952 */
953
954/* Maximum lock time can be 270 * PDIV cycles */
955#define PLL2550XX_LOCK_FACTOR 270
956
957#define PLL2550XX_M_MASK 0x3FF
958#define PLL2550XX_P_MASK 0x3F
959#define PLL2550XX_S_MASK 0x7
960#define PLL2550XX_LOCK_STAT_MASK 0x1
961#define PLL2550XX_M_SHIFT 9
962#define PLL2550XX_P_SHIFT 3
963#define PLL2550XX_S_SHIFT 0
964#define PLL2550XX_LOCK_STAT_SHIFT 21
965
966static unsigned long samsung_pll2550xx_recalc_rate(struct clk_hw *hw,
967 unsigned long parent_rate)
968{
969 struct samsung_clk_pll *pll = to_clk_pll(hw);
970 u32 mdiv, pdiv, sdiv, pll_con;
971 u64 fvco = parent_rate;
972
973 pll_con = __raw_readl(pll->con_reg);
974 mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
975 pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
976 sdiv = (pll_con >> PLL2550XX_S_SHIFT) & PLL2550XX_S_MASK;
977
978 fvco *= mdiv;
979 do_div(fvco, (pdiv << sdiv));
980
981 return (unsigned long)fvco;
982}
983
984static inline bool samsung_pll2550xx_mp_change(u32 mdiv, u32 pdiv, u32 pll_con)
985{
986 u32 old_mdiv, old_pdiv;
987
988 old_mdiv = (pll_con >> PLL2550XX_M_SHIFT) & PLL2550XX_M_MASK;
989 old_pdiv = (pll_con >> PLL2550XX_P_SHIFT) & PLL2550XX_P_MASK;
990
991 return mdiv != old_mdiv || pdiv != old_pdiv;
992}
993
994static int samsung_pll2550xx_set_rate(struct clk_hw *hw, unsigned long drate,
995 unsigned long prate)
996{
997 struct samsung_clk_pll *pll = to_clk_pll(hw);
998 const struct samsung_pll_rate_table *rate;
999 u32 tmp;
1000
1001 /* Get required rate settings from table */
1002 rate = samsung_get_pll_settings(pll, drate);
1003 if (!rate) {
1004 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1005 drate, __clk_get_name(hw->clk));
1006 return -EINVAL;
1007 }
1008
1009 tmp = __raw_readl(pll->con_reg);
1010
1011 if (!(samsung_pll2550xx_mp_change(rate->mdiv, rate->pdiv, tmp))) {
1012 /* If only s change, change just s value only*/
1013 tmp &= ~(PLL2550XX_S_MASK << PLL2550XX_S_SHIFT);
1014 tmp |= rate->sdiv << PLL2550XX_S_SHIFT;
1015 __raw_writel(tmp, pll->con_reg);
1016
1017 return 0;
1018 }
1019
1020 /* Set PLL lock time. */
1021 __raw_writel(rate->pdiv * PLL2550XX_LOCK_FACTOR, pll->lock_reg);
1022
1023 /* Change PLL PMS values */
1024 tmp &= ~((PLL2550XX_M_MASK << PLL2550XX_M_SHIFT) |
1025 (PLL2550XX_P_MASK << PLL2550XX_P_SHIFT) |
1026 (PLL2550XX_S_MASK << PLL2550XX_S_SHIFT));
1027 tmp |= (rate->mdiv << PLL2550XX_M_SHIFT) |
1028 (rate->pdiv << PLL2550XX_P_SHIFT) |
1029 (rate->sdiv << PLL2550XX_S_SHIFT);
1030 __raw_writel(tmp, pll->con_reg);
1031
1032 /* wait_lock_time */
1033 do {
1034 cpu_relax();
1035 tmp = __raw_readl(pll->con_reg);
1036 } while (!(tmp & (PLL2550XX_LOCK_STAT_MASK
1037 << PLL2550XX_LOCK_STAT_SHIFT)));
1038
1039 return 0;
1040}
1041
1042static const struct clk_ops samsung_pll2550xx_clk_ops = {
1043 .recalc_rate = samsung_pll2550xx_recalc_rate,
1044 .round_rate = samsung_pll_round_rate,
1045 .set_rate = samsung_pll2550xx_set_rate,
1046};
1047
1048static const struct clk_ops samsung_pll2550xx_clk_min_ops = {
1049 .recalc_rate = samsung_pll2550xx_recalc_rate,
1050};
1051
Rahul Sharmaeefe1192014-03-12 20:26:46 +05301052/*
1053 * PLL2650XX Clock Type
1054 */
1055
1056/* Maximum lock time can be 3000 * PDIV cycles */
1057#define PLL2650XX_LOCK_FACTOR 3000
1058
1059#define PLL2650XX_MDIV_SHIFT 9
1060#define PLL2650XX_PDIV_SHIFT 3
1061#define PLL2650XX_SDIV_SHIFT 0
1062#define PLL2650XX_KDIV_SHIFT 0
1063#define PLL2650XX_MDIV_MASK 0x1ff
1064#define PLL2650XX_PDIV_MASK 0x3f
1065#define PLL2650XX_SDIV_MASK 0x7
1066#define PLL2650XX_KDIV_MASK 0xffff
1067#define PLL2650XX_PLL_ENABLE_SHIFT 23
1068#define PLL2650XX_PLL_LOCKTIME_SHIFT 21
1069#define PLL2650XX_PLL_FOUTMASK_SHIFT 31
1070
1071static unsigned long samsung_pll2650xx_recalc_rate(struct clk_hw *hw,
1072 unsigned long parent_rate)
1073{
1074 struct samsung_clk_pll *pll = to_clk_pll(hw);
1075 u32 mdiv, pdiv, sdiv, pll_con0, pll_con2;
1076 s16 kdiv;
1077 u64 fvco = parent_rate;
1078
1079 pll_con0 = __raw_readl(pll->con_reg);
1080 pll_con2 = __raw_readl(pll->con_reg + 8);
1081 mdiv = (pll_con0 >> PLL2650XX_MDIV_SHIFT) & PLL2650XX_MDIV_MASK;
1082 pdiv = (pll_con0 >> PLL2650XX_PDIV_SHIFT) & PLL2650XX_PDIV_MASK;
1083 sdiv = (pll_con0 >> PLL2650XX_SDIV_SHIFT) & PLL2650XX_SDIV_MASK;
1084 kdiv = (s16)(pll_con2 & PLL2650XX_KDIV_MASK);
1085
1086 fvco *= (mdiv << 16) + kdiv;
1087 do_div(fvco, (pdiv << sdiv));
1088 fvco >>= 16;
1089
1090 return (unsigned long)fvco;
1091}
1092
1093static int samsung_pll2650xx_set_rate(struct clk_hw *hw, unsigned long drate,
1094 unsigned long parent_rate)
1095{
1096 struct samsung_clk_pll *pll = to_clk_pll(hw);
1097 u32 tmp, pll_con0, pll_con2;
1098 const struct samsung_pll_rate_table *rate;
1099
1100 rate = samsung_get_pll_settings(pll, drate);
1101 if (!rate) {
1102 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
1103 drate, __clk_get_name(hw->clk));
1104 return -EINVAL;
1105 }
1106
1107 pll_con0 = __raw_readl(pll->con_reg);
1108 pll_con2 = __raw_readl(pll->con_reg + 8);
1109
1110 /* Change PLL PMS values */
1111 pll_con0 &= ~(PLL2650XX_MDIV_MASK << PLL2650XX_MDIV_SHIFT |
1112 PLL2650XX_PDIV_MASK << PLL2650XX_PDIV_SHIFT |
1113 PLL2650XX_SDIV_MASK << PLL2650XX_SDIV_SHIFT);
1114 pll_con0 |= rate->mdiv << PLL2650XX_MDIV_SHIFT;
1115 pll_con0 |= rate->pdiv << PLL2650XX_PDIV_SHIFT;
1116 pll_con0 |= rate->sdiv << PLL2650XX_SDIV_SHIFT;
1117 pll_con0 |= 1 << PLL2650XX_PLL_ENABLE_SHIFT;
1118 pll_con0 |= 1 << PLL2650XX_PLL_FOUTMASK_SHIFT;
1119
1120 pll_con2 &= ~(PLL2650XX_KDIV_MASK << PLL2650XX_KDIV_SHIFT);
1121 pll_con2 |= ((~(rate->kdiv) + 1) & PLL2650XX_KDIV_MASK)
1122 << PLL2650XX_KDIV_SHIFT;
1123
1124 /* Set PLL lock time. */
1125 __raw_writel(PLL2650XX_LOCK_FACTOR * rate->pdiv, pll->lock_reg);
1126
1127 __raw_writel(pll_con0, pll->con_reg);
1128 __raw_writel(pll_con2, pll->con_reg + 8);
1129
1130 do {
1131 tmp = __raw_readl(pll->con_reg);
1132 } while (!(tmp & (0x1 << PLL2650XX_PLL_LOCKTIME_SHIFT)));
1133
1134 return 0;
1135}
1136
1137static const struct clk_ops samsung_pll2650xx_clk_ops = {
1138 .recalc_rate = samsung_pll2650xx_recalc_rate,
1139 .set_rate = samsung_pll2650xx_set_rate,
1140 .round_rate = samsung_pll_round_rate,
1141};
1142
1143static const struct clk_ops samsung_pll2650xx_clk_min_ops = {
1144 .recalc_rate = samsung_pll2650xx_recalc_rate,
1145};
1146
Rahul Sharma976face2014-03-12 20:26:44 +05301147static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1148 struct samsung_pll_clock *pll_clk,
1149 void __iomem *base)
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301150{
1151 struct samsung_clk_pll *pll;
1152 struct clk *clk;
1153 struct clk_init_data init;
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +05301154 int ret, len;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301155
1156 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
1157 if (!pll) {
1158 pr_err("%s: could not allocate pll clk %s\n",
1159 __func__, pll_clk->name);
1160 return;
1161 }
1162
1163 init.name = pll_clk->name;
1164 init.flags = pll_clk->flags;
1165 init.parent_names = &pll_clk->parent_name;
1166 init.num_parents = 1;
1167
Yadwinder Singh Brar3ff6e0d2013-06-11 15:01:12 +05301168 if (pll_clk->rate_table) {
1169 /* find count of rates in rate_table */
1170 for (len = 0; pll_clk->rate_table[len].rate != 0; )
1171 len++;
1172
1173 pll->rate_count = len;
1174 pll->rate_table = kmemdup(pll_clk->rate_table,
1175 pll->rate_count *
1176 sizeof(struct samsung_pll_rate_table),
1177 GFP_KERNEL);
1178 WARN(!pll->rate_table,
1179 "%s: could not allocate rate table for %s\n",
1180 __func__, pll_clk->name);
1181 }
1182
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301183 switch (pll_clk->type) {
Heiko Stuebnera951b1d2014-02-19 09:25:41 +09001184 case pll_2126:
1185 init.ops = &samsung_pll2126_clk_ops;
1186 break;
1187 case pll_3000:
1188 init.ops = &samsung_pll3000_clk_ops;
1189 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301190 /* clk_ops for 35xx and 2550 are similar */
1191 case pll_35xx:
1192 case pll_2550:
Yadwinder Singh Brardfa89312013-06-11 15:01:13 +05301193 if (!pll->rate_table)
1194 init.ops = &samsung_pll35xx_clk_min_ops;
1195 else
1196 init.ops = &samsung_pll35xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301197 break;
Tomasz Figa52b06012013-08-26 19:09:04 +02001198 case pll_4500:
Tomasz Figab4054ac2013-08-26 19:09:05 +02001199 init.ops = &samsung_pll45xx_clk_min_ops;
1200 break;
Tomasz Figa52b06012013-08-26 19:09:04 +02001201 case pll_4502:
1202 case pll_4508:
Tomasz Figab4054ac2013-08-26 19:09:05 +02001203 if (!pll->rate_table)
1204 init.ops = &samsung_pll45xx_clk_min_ops;
1205 else
1206 init.ops = &samsung_pll45xx_clk_ops;
Tomasz Figa52b06012013-08-26 19:09:04 +02001207 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301208 /* clk_ops for 36xx and 2650 are similar */
1209 case pll_36xx:
1210 case pll_2650:
Vikas Sajjanbb4278d2013-06-11 15:01:14 +05301211 if (!pll->rate_table)
1212 init.ops = &samsung_pll36xx_clk_min_ops;
1213 else
1214 init.ops = &samsung_pll36xx_clk_ops;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301215 break;
Tomasz Figa40ef7232013-08-21 02:33:21 +02001216 case pll_6552:
Heiko Stuebner06654ac2014-02-19 09:25:36 +09001217 case pll_6552_s3c2416:
Tomasz Figa40ef7232013-08-21 02:33:21 +02001218 init.ops = &samsung_pll6552_clk_ops;
1219 break;
1220 case pll_6553:
1221 init.ops = &samsung_pll6553_clk_ops;
1222 break;
Tomasz Figac50d11f2013-08-26 19:09:06 +02001223 case pll_4600:
1224 case pll_4650:
1225 case pll_4650c:
Tomasz Figa5c896582013-08-26 19:09:07 +02001226 if (!pll->rate_table)
1227 init.ops = &samsung_pll46xx_clk_min_ops;
1228 else
1229 init.ops = &samsung_pll46xx_clk_ops;
Tomasz Figac50d11f2013-08-26 19:09:06 +02001230 break;
Heiko Stuebnerea5d6a82014-02-25 09:50:43 +09001231 case pll_s3c2410_mpll:
1232 if (!pll->rate_table)
1233 init.ops = &samsung_s3c2410_mpll_clk_min_ops;
1234 else
1235 init.ops = &samsung_s3c2410_mpll_clk_ops;
1236 break;
1237 case pll_s3c2410_upll:
1238 if (!pll->rate_table)
1239 init.ops = &samsung_s3c2410_upll_clk_min_ops;
1240 else
1241 init.ops = &samsung_s3c2410_upll_clk_ops;
1242 break;
1243 case pll_s3c2440_mpll:
1244 if (!pll->rate_table)
1245 init.ops = &samsung_s3c2440_mpll_clk_min_ops;
1246 else
1247 init.ops = &samsung_s3c2440_mpll_clk_ops;
1248 break;
Pankaj Dubey84329842014-03-12 20:26:45 +05301249 case pll_2550xx:
1250 if (!pll->rate_table)
1251 init.ops = &samsung_pll2550xx_clk_min_ops;
1252 else
1253 init.ops = &samsung_pll2550xx_clk_ops;
1254 break;
Rahul Sharmaeefe1192014-03-12 20:26:46 +05301255 case pll_2650xx:
1256 if (!pll->rate_table)
1257 init.ops = &samsung_pll2650xx_clk_min_ops;
1258 else
1259 init.ops = &samsung_pll2650xx_clk_ops;
1260 break;
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301261 default:
1262 pr_warn("%s: Unknown pll type for pll clk %s\n",
1263 __func__, pll_clk->name);
1264 }
1265
1266 pll->hw.init = &init;
1267 pll->type = pll_clk->type;
1268 pll->lock_reg = base + pll_clk->lock_offset;
1269 pll->con_reg = base + pll_clk->con_offset;
1270
1271 clk = clk_register(NULL, &pll->hw);
1272 if (IS_ERR(clk)) {
1273 pr_err("%s: failed to register pll clock %s : %ld\n",
1274 __func__, pll_clk->name, PTR_ERR(clk));
1275 kfree(pll);
1276 return;
1277 }
1278
Rahul Sharma976face2014-03-12 20:26:44 +05301279 samsung_clk_add_lookup(ctx, clk, pll_clk->id);
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301280
1281 if (!pll_clk->alias)
1282 return;
1283
1284 ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
1285 if (ret)
1286 pr_err("%s: failed to register lookup for %s : %d",
1287 __func__, pll_clk->name, ret);
1288}
1289
Rahul Sharma976face2014-03-12 20:26:44 +05301290void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
1291 struct samsung_pll_clock *pll_list,
1292 unsigned int nr_pll, void __iomem *base)
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301293{
1294 int cnt;
1295
1296 for (cnt = 0; cnt < nr_pll; cnt++)
Rahul Sharma976face2014-03-12 20:26:44 +05301297 _samsung_clk_register_pll(ctx, &pll_list[cnt], base);
Yadwinder Singh Brar07dc76f2013-06-11 15:01:07 +05301298}