Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pll.h
Go to the documentation of this file.
1 /* linux/arch/arm/plat-samsung/include/plat/pll.h
2  *
3  * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
4  * http://www.samsung.com/
5  *
6  * Copyright 2008 Openmoko, Inc.
7  * Copyright 2008 Simtec Electronics
8  * Ben Dooks <[email protected]>
9  * http://armlinux.simtec.co.uk/
10  *
11  * Samsung PLL codes
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2 as
15  * published by the Free Software Foundation.
16 */
17 
18 #include <asm/div64.h>
19 
20 #define S3C24XX_PLL_MDIV_MASK (0xFF)
21 #define S3C24XX_PLL_PDIV_MASK (0x1F)
22 #define S3C24XX_PLL_SDIV_MASK (0x3)
23 #define S3C24XX_PLL_MDIV_SHIFT (12)
24 #define S3C24XX_PLL_PDIV_SHIFT (4)
25 #define S3C24XX_PLL_SDIV_SHIFT (0)
26 
27 static inline unsigned int s3c24xx_get_pll(unsigned int pllval,
28  unsigned int baseclk)
29 {
30  unsigned int mdiv, pdiv, sdiv;
31  uint64_t fvco;
32 
33  mdiv = (pllval >> S3C24XX_PLL_MDIV_SHIFT) & S3C24XX_PLL_MDIV_MASK;
34  pdiv = (pllval >> S3C24XX_PLL_PDIV_SHIFT) & S3C24XX_PLL_PDIV_MASK;
35  sdiv = (pllval >> S3C24XX_PLL_SDIV_SHIFT) & S3C24XX_PLL_SDIV_MASK;
36 
37  fvco = (uint64_t)baseclk * (mdiv + 8);
38  do_div(fvco, (pdiv + 2) << sdiv);
39 
40  return (unsigned int)fvco;
41 }
42 
43 #define S3C2416_PLL_MDIV_MASK (0x3FF)
44 #define S3C2416_PLL_PDIV_MASK (0x3F)
45 #define S3C2416_PLL_SDIV_MASK (0x7)
46 #define S3C2416_PLL_MDIV_SHIFT (14)
47 #define S3C2416_PLL_PDIV_SHIFT (5)
48 #define S3C2416_PLL_SDIV_SHIFT (0)
49 
50 static inline unsigned int s3c2416_get_pll(unsigned int pllval,
51  unsigned int baseclk)
52 {
53  unsigned int mdiv, pdiv, sdiv;
54  uint64_t fvco;
55 
56  mdiv = (pllval >> S3C2416_PLL_MDIV_SHIFT) & S3C2416_PLL_MDIV_MASK;
57  pdiv = (pllval >> S3C2416_PLL_PDIV_SHIFT) & S3C2416_PLL_PDIV_MASK;
58  sdiv = (pllval >> S3C2416_PLL_SDIV_SHIFT) & S3C2416_PLL_SDIV_MASK;
59 
60  fvco = (uint64_t)baseclk * mdiv;
61  do_div(fvco, (pdiv << sdiv));
62 
63  return (unsigned int)fvco;
64 }
65 
66 #define S3C6400_PLL_MDIV_MASK (0x3FF)
67 #define S3C6400_PLL_PDIV_MASK (0x3F)
68 #define S3C6400_PLL_SDIV_MASK (0x7)
69 #define S3C6400_PLL_MDIV_SHIFT (16)
70 #define S3C6400_PLL_PDIV_SHIFT (8)
71 #define S3C6400_PLL_SDIV_SHIFT (0)
72 
73 static inline unsigned long s3c6400_get_pll(unsigned long baseclk,
74  u32 pllcon)
75 {
76  u32 mdiv, pdiv, sdiv;
77  u64 fvco = baseclk;
78 
79  mdiv = (pllcon >> S3C6400_PLL_MDIV_SHIFT) & S3C6400_PLL_MDIV_MASK;
80  pdiv = (pllcon >> S3C6400_PLL_PDIV_SHIFT) & S3C6400_PLL_PDIV_MASK;
81  sdiv = (pllcon >> S3C6400_PLL_SDIV_SHIFT) & S3C6400_PLL_SDIV_MASK;
82 
83  fvco *= mdiv;
84  do_div(fvco, (pdiv << sdiv));
85 
86  return (unsigned long)fvco;
87 }
88 
89 #define PLL6553X_MDIV_MASK (0x7F)
90 #define PLL6553X_PDIV_MASK (0x1F)
91 #define PLL6553X_SDIV_MASK (0x3)
92 #define PLL6553X_KDIV_MASK (0xFFFF)
93 #define PLL6553X_MDIV_SHIFT (16)
94 #define PLL6553X_PDIV_SHIFT (8)
95 #define PLL6553X_SDIV_SHIFT (0)
96 
97 static inline unsigned long s3c_get_pll6553x(unsigned long baseclk,
98  u32 pll_con0, u32 pll_con1)
99 {
100  unsigned long result;
101  u32 mdiv, pdiv, sdiv, kdiv;
102  u64 tmp;
103 
104  mdiv = (pll_con0 >> PLL6553X_MDIV_SHIFT) & PLL6553X_MDIV_MASK;
105  pdiv = (pll_con0 >> PLL6553X_PDIV_SHIFT) & PLL6553X_PDIV_MASK;
106  sdiv = (pll_con0 >> PLL6553X_SDIV_SHIFT) & PLL6553X_SDIV_MASK;
107  kdiv = pll_con1 & PLL6553X_KDIV_MASK;
108 
109  /*
110  * We need to multiple baseclk by mdiv (the integer part) and kdiv
111  * which is in 2^16ths, so shift mdiv up (does not overflow) and
112  * add kdiv before multiplying. The use of tmp is to avoid any
113  * overflows before shifting bac down into result when multipling
114  * by the mdiv and kdiv pair.
115  */
116 
117  tmp = baseclk;
118  tmp *= (mdiv << 16) + kdiv;
119  do_div(tmp, (pdiv << sdiv));
120  result = tmp >> 16;
121 
122  return result;
123 }
124 
125 #define PLL35XX_MDIV_MASK (0x3FF)
126 #define PLL35XX_PDIV_MASK (0x3F)
127 #define PLL35XX_SDIV_MASK (0x7)
128 #define PLL35XX_MDIV_SHIFT (16)
129 #define PLL35XX_PDIV_SHIFT (8)
130 #define PLL35XX_SDIV_SHIFT (0)
131 
132 static inline unsigned long s5p_get_pll35xx(unsigned long baseclk, u32 pll_con)
133 {
134  u32 mdiv, pdiv, sdiv;
135  u64 fvco = baseclk;
136 
137  mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
138  pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
139  sdiv = (pll_con >> PLL35XX_SDIV_SHIFT) & PLL35XX_SDIV_MASK;
140 
141  fvco *= mdiv;
142  do_div(fvco, (pdiv << sdiv));
143 
144  return (unsigned long)fvco;
145 }
146 
147 #define PLL36XX_KDIV_MASK (0xFFFF)
148 #define PLL36XX_MDIV_MASK (0x1FF)
149 #define PLL36XX_PDIV_MASK (0x3F)
150 #define PLL36XX_SDIV_MASK (0x7)
151 #define PLL36XX_MDIV_SHIFT (16)
152 #define PLL36XX_PDIV_SHIFT (8)
153 #define PLL36XX_SDIV_SHIFT (0)
154 
155 static inline unsigned long s5p_get_pll36xx(unsigned long baseclk,
156  u32 pll_con0, u32 pll_con1)
157 {
158  unsigned long result;
159  u32 mdiv, pdiv, sdiv, kdiv;
160  u64 tmp;
161 
162  mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
163  pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
164  sdiv = (pll_con0 >> PLL36XX_SDIV_SHIFT) & PLL36XX_SDIV_MASK;
165  kdiv = pll_con1 & PLL36XX_KDIV_MASK;
166 
167  tmp = baseclk;
168 
169  tmp *= (mdiv << 16) + kdiv;
170  do_div(tmp, (pdiv << sdiv));
171  result = tmp >> 16;
172 
173  return result;
174 }
175 
176 #define PLL45XX_MDIV_MASK (0x3FF)
177 #define PLL45XX_PDIV_MASK (0x3F)
178 #define PLL45XX_SDIV_MASK (0x7)
179 #define PLL45XX_MDIV_SHIFT (16)
180 #define PLL45XX_PDIV_SHIFT (8)
181 #define PLL45XX_SDIV_SHIFT (0)
182 
187 };
188 
189 static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
190  enum pll45xx_type_t pll_type)
191 {
192  u32 mdiv, pdiv, sdiv;
193  u64 fvco = baseclk;
194 
195  mdiv = (pll_con >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
196  pdiv = (pll_con >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
197  sdiv = (pll_con >> PLL45XX_SDIV_SHIFT) & PLL45XX_SDIV_MASK;
198 
199  if (pll_type == pll_4508)
200  sdiv = sdiv - 1;
201 
202  fvco *= mdiv;
203  do_div(fvco, (pdiv << sdiv));
204 
205  return (unsigned long)fvco;
206 }
207 
208 /* CON0 bit-fields */
209 #define PLL46XX_MDIV_MASK (0x1FF)
210 #define PLL46XX_PDIV_MASK (0x3F)
211 #define PLL46XX_SDIV_MASK (0x7)
212 #define PLL46XX_LOCKED_SHIFT (29)
213 #define PLL46XX_MDIV_SHIFT (16)
214 #define PLL46XX_PDIV_SHIFT (8)
215 #define PLL46XX_SDIV_SHIFT (0)
216 
217 /* CON1 bit-fields */
218 #define PLL46XX_MRR_MASK (0x1F)
219 #define PLL46XX_MFR_MASK (0x3F)
220 #define PLL46XX_KDIV_MASK (0xFFFF)
221 #define PLL4650C_KDIV_MASK (0xFFF)
222 #define PLL46XX_MRR_SHIFT (24)
223 #define PLL46XX_MFR_SHIFT (16)
224 #define PLL46XX_KDIV_SHIFT (0)
225 
230 };
231 
232 static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
233  u32 pll_con0, u32 pll_con1,
234  enum pll46xx_type_t pll_type)
235 {
236  unsigned long result;
237  u32 mdiv, pdiv, sdiv, kdiv;
238  u64 tmp;
239 
240  mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
241  pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
242  sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
243  kdiv = pll_con1 & PLL46XX_KDIV_MASK;
244 
245  if (pll_type == pll_4650c)
246  kdiv = pll_con1 & PLL4650C_KDIV_MASK;
247  else
248  kdiv = pll_con1 & PLL46XX_KDIV_MASK;
249 
250  tmp = baseclk;
251 
252  if (pll_type == pll_4600) {
253  tmp *= (mdiv << 16) + kdiv;
254  do_div(tmp, (pdiv << sdiv));
255  result = tmp >> 16;
256  } else {
257  tmp *= (mdiv << 10) + kdiv;
258  do_div(tmp, (pdiv << sdiv));
259  result = tmp >> 10;
260  }
261 
262  return result;
263 }
264 
265 #define PLL90XX_MDIV_MASK (0xFF)
266 #define PLL90XX_PDIV_MASK (0x3F)
267 #define PLL90XX_SDIV_MASK (0x7)
268 #define PLL90XX_KDIV_MASK (0xffff)
269 #define PLL90XX_LOCKED_SHIFT (29)
270 #define PLL90XX_MDIV_SHIFT (16)
271 #define PLL90XX_PDIV_SHIFT (8)
272 #define PLL90XX_SDIV_SHIFT (0)
273 #define PLL90XX_KDIV_SHIFT (0)
274 
275 static inline unsigned long s5p_get_pll90xx(unsigned long baseclk,
276  u32 pll_con, u32 pll_conk)
277 {
278  unsigned long result;
279  u32 mdiv, pdiv, sdiv, kdiv;
280  u64 tmp;
281 
282  mdiv = (pll_con >> PLL90XX_MDIV_SHIFT) & PLL90XX_MDIV_MASK;
283  pdiv = (pll_con >> PLL90XX_PDIV_SHIFT) & PLL90XX_PDIV_MASK;
284  sdiv = (pll_con >> PLL90XX_SDIV_SHIFT) & PLL90XX_SDIV_MASK;
285  kdiv = pll_conk & PLL90XX_KDIV_MASK;
286 
287  /*
288  * We need to multiple baseclk by mdiv (the integer part) and kdiv
289  * which is in 2^16ths, so shift mdiv up (does not overflow) and
290  * add kdiv before multiplying. The use of tmp is to avoid any
291  * overflows before shifting bac down into result when multipling
292  * by the mdiv and kdiv pair.
293  */
294 
295  tmp = baseclk;
296  tmp *= (mdiv << 16) + kdiv;
297  do_div(tmp, (pdiv << sdiv));
298  result = tmp >> 16;
299 
300  return result;
301 }
302 
303 #define PLL65XX_MDIV_MASK (0x3FF)
304 #define PLL65XX_PDIV_MASK (0x3F)
305 #define PLL65XX_SDIV_MASK (0x7)
306 #define PLL65XX_MDIV_SHIFT (16)
307 #define PLL65XX_PDIV_SHIFT (8)
308 #define PLL65XX_SDIV_SHIFT (0)
309 
310 static inline unsigned long s5p_get_pll65xx(unsigned long baseclk, u32 pll_con)
311 {
312  u32 mdiv, pdiv, sdiv;
313  u64 fvco = baseclk;
314 
315  mdiv = (pll_con >> PLL65XX_MDIV_SHIFT) & PLL65XX_MDIV_MASK;
316  pdiv = (pll_con >> PLL65XX_PDIV_SHIFT) & PLL65XX_PDIV_MASK;
317  sdiv = (pll_con >> PLL65XX_SDIV_SHIFT) & PLL65XX_SDIV_MASK;
318 
319  fvco *= mdiv;
320  do_div(fvco, (pdiv << sdiv));
321 
322  return (unsigned long)fvco;
323 }