1 /* linux/arch/arm/plat-samsung/include/plat/pll.h
3 * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * Copyright 2008 Openmoko, Inc.
7 * Copyright 2008 Simtec Electronics
8 * Ben Dooks <ben@simtec.co.uk>
9 * http://armlinux.simtec.co.uk/
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.
18 #include <asm/div64.h>
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)
27 static inline unsigned int s3c24xx_get_pll(unsigned int pllval
,
30 unsigned int mdiv
, pdiv
, sdiv
;
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
;
37 fvco
= (uint64_t)baseclk
* (mdiv
+ 8);
38 do_div(fvco
, (pdiv
+ 2) << sdiv
);
40 return (unsigned int)fvco
;
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)
50 static inline unsigned int s3c2416_get_pll(unsigned int pllval
,
53 unsigned int mdiv
, pdiv
, sdiv
;
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
;
60 fvco
= (uint64_t)baseclk
* mdiv
;
61 do_div(fvco
, (pdiv
<< sdiv
));
63 return (unsigned int)fvco
;
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)
73 static inline unsigned long s3c6400_get_pll(unsigned long baseclk
,
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
;
84 do_div(fvco
, (pdiv
<< sdiv
));
86 return (unsigned long)fvco
;
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)
97 static inline unsigned long s3c_get_pll6553x(unsigned long baseclk
,
98 u32 pll_con0
, u32 pll_con1
)
100 unsigned long result
;
101 u32 mdiv
, pdiv
, sdiv
, kdiv
;
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
;
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.
118 tmp
*= (mdiv
<< 16) + kdiv
;
119 do_div(tmp
, (pdiv
<< sdiv
));
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)
132 static inline unsigned long s5p_get_pll35xx(unsigned long baseclk
, u32 pll_con
)
134 u32 mdiv
, pdiv
, sdiv
;
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
;
142 do_div(fvco
, (pdiv
<< sdiv
));
144 return (unsigned long)fvco
;
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)
155 static inline unsigned long s5p_get_pll36xx(unsigned long baseclk
,
156 u32 pll_con0
, u32 pll_con1
)
158 unsigned long result
;
159 u32 mdiv
, pdiv
, sdiv
, kdiv
;
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
;
169 tmp
*= (mdiv
<< 16) + kdiv
;
170 do_div(tmp
, (pdiv
<< sdiv
));
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)
183 enum pll45xx_type_t
{
189 static inline unsigned long s5p_get_pll45xx(unsigned long baseclk
, u32 pll_con
,
190 enum pll45xx_type_t pll_type
)
192 u32 mdiv
, pdiv
, sdiv
;
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
;
199 if (pll_type
== pll_4508
)
203 do_div(fvco
, (pdiv
<< sdiv
));
205 return (unsigned long)fvco
;
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)
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)
226 enum pll46xx_type_t
{
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
)
236 unsigned long result
;
237 u32 mdiv
, pdiv
, sdiv
, kdiv
;
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
;
245 if (pll_type
== pll_4650c
)
246 kdiv
= pll_con1
& PLL4650C_KDIV_MASK
;
248 kdiv
= pll_con1
& PLL46XX_KDIV_MASK
;
252 if (pll_type
== pll_4600
) {
253 tmp
*= (mdiv
<< 16) + kdiv
;
254 do_div(tmp
, (pdiv
<< sdiv
));
257 tmp
*= (mdiv
<< 10) + kdiv
;
258 do_div(tmp
, (pdiv
<< sdiv
));
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)
275 static inline unsigned long s5p_get_pll90xx(unsigned long baseclk
,
276 u32 pll_con
, u32 pll_conk
)
278 unsigned long result
;
279 u32 mdiv
, pdiv
, sdiv
, kdiv
;
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
;
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.
296 tmp
*= (mdiv
<< 16) + kdiv
;
297 do_div(tmp
, (pdiv
<< sdiv
));
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)
310 static inline unsigned long s5p_get_pll65xx(unsigned long baseclk
, u32 pll_con
)
312 u32 mdiv
, pdiv
, sdiv
;
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
;
320 do_div(fvco
, (pdiv
<< sdiv
));
322 return (unsigned long)fvco
;