Commit | Line | Data |
---|---|---|
52e329eb KK |
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 <ben@simtec.co.uk> | |
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 | ||
183 | enum pll45xx_type_t { | |
184 | pll_4500, | |
185 | pll_4502, | |
186 | pll_4508 | |
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 | ||
226 | enum pll46xx_type_t { | |
227 | pll_4600, | |
228 | pll_4650, | |
229 | pll_4650c, | |
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 | } |