]> git.ipfire.org Git - people/ms/u-boot.git/blame - arch/powerpc/cpu/ppc4xx/speed.c
Merge branch 'master' of git://git.denx.de/u-boot-nds32
[people/ms/u-boot.git] / arch / powerpc / cpu / ppc4xx / speed.c
CommitLineData
c609719b 1/*
2801b2d2 2 * (C) Copyright 2000-2008
c609719b
WD
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
1a459660 5 * SPDX-License-Identifier: GPL-2.0+
c609719b
WD
6 */
7
8#include <common.h>
9#include <ppc_asm.tmpl>
b36df561 10#include <asm/ppc4xx.h>
c609719b
WD
11#include <asm/processor.h>
12
d87080b7 13DECLARE_GLOBAL_DATA_PTR;
c609719b
WD
14
15#define ONE_BILLION 1000000000
6c5879f3
MB
16#ifdef DEBUG
17#define DEBUGF(fmt,args...) printf(fmt ,##args)
18#else
19#define DEBUGF(fmt,args...)
20#endif
c609719b 21
2801b2d2
SR
22#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
23
c609719b
WD
24#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
25
087dfdb7 26void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
c609719b
WD
27{
28 unsigned long pllmr;
29 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
30 uint pvr = get_pvr();
31 unsigned long psr;
32 unsigned long m;
33
34 /*
35 * Read PLL Mode register
36 */
d1c3b275 37 pllmr = mfdcr (CPC0_PLLMR);
c609719b
WD
38
39 /*
40 * Read Pin Strapping register
41 */
d1c3b275 42 psr = mfdcr (CPC0_PSR);
c609719b
WD
43
44 /*
45 * Determine FWD_DIV.
46 */
47 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
48
49 /*
50 * Determine FBK_DIV.
51 */
52 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
53 if (sysInfo->pllFbkDiv == 0) {
54 sysInfo->pllFbkDiv = 16;
55 }
56
57 /*
58 * Determine PLB_DIV.
59 */
60 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
61
62 /*
63 * Determine PCI_DIV.
64 */
65 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
66
67 /*
68 * Determine EXTBUS_DIV.
69 */
70 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
71
72 /*
73 * Determine OPB_DIV.
74 */
75 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
76
77 /*
78 * Check if PPC405GPr used (mask minor revision field)
79 */
baa3d528 80 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
c609719b
WD
81 /*
82 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
83 */
84 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
85
86 /*
87 * Determine factor m depending on PLL feedback clock source
88 */
89 if (!(psr & PSR_PCI_ASYNC_EN)) {
90 if (psr & PSR_NEW_MODE_EN) {
91 /*
92 * sync pci clock used as feedback (new mode)
93 */
94 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
95 } else {
96 /*
97 * sync pci clock used as feedback (legacy mode)
98 */
99 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
100 }
101 } else if (psr & PSR_NEW_MODE_EN) {
102 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
103 /*
104 * PerClk used as feedback (new mode)
105 */
106 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
107 } else {
108 /*
109 * CPU clock used as feedback (new mode)
110 */
111 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
112 }
113 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
114 /*
115 * PerClk used as feedback (legacy mode)
116 */
117 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
118 } else {
119 /*
120 * PLB clock used as feedback (legacy mode)
121 */
122 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
123 }
124
b39392a9
SR
125 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
126 (unsigned long long)sysClkPeriodPs;
127 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
128 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
c609719b
WD
129 } else {
130 /*
131 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
132 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
133 * to make sure it is within the proper range.
134 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
8ed44d91 135 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
c609719b
WD
136 */
137 if (sysInfo->pllFwdDiv == 1) {
138 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
139 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
140 } else {
b39392a9
SR
141 sysInfo->freqVCOHz = ( 1000000000000LL *
142 (unsigned long long)sysInfo->pllFwdDiv *
143 (unsigned long long)sysInfo->pllFbkDiv *
144 (unsigned long long)sysInfo->pllPlbDiv
145 ) / (unsigned long long)sysClkPeriodPs;
146 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
147 sysInfo->pllFbkDiv)) * 10000;
148 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
c609719b
WD
149 }
150 }
fa8aea20 151
e67af44d 152 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
e1d09680 153 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
fa8aea20 154 sysInfo->freqUART = sysInfo->freqProcessor;
c609719b
WD
155}
156
157
c609719b
WD
158/********************************************
159 * get_PCI_freq
160 * return PCI bus freq in Hz
161 *********************************************/
162ulong get_PCI_freq (void)
163{
164 ulong val;
087dfdb7 165 PPC4xx_SYS_INFO sys_info;
c609719b
WD
166
167 get_sys_info (&sys_info);
168 val = sys_info.freqPLB / sys_info.pllPciDiv;
169 return val;
170}
171
172
173#elif defined(CONFIG_440)
c157d8e2 174
7d307936 175#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
1b8fec13 176 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
2801b2d2
SR
177static u8 pll_fwdv_multi_bits[] = {
178 /* values for: 1 - 16 */
179 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
180 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
181};
182
183u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
184{
185 u32 index;
186
187 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
188 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
189 return index + 1;
190
191 return 0;
192}
193
194static u8 pll_fbdv_multi_bits[] = {
195 /* values for: 1 - 100 */
196 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
197 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
198 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
199 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
200 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
201 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
202 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
203 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
204 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
205 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
206 /* values for: 101 - 200 */
207 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
208 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
b9bbefce 209 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
2801b2d2
SR
210 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
211 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
212 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
213 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
214 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
215 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
216 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
217 /* values for: 201 - 255 */
218 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
219 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
220 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
221 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
222 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
223 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
224};
225
226u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
227{
228 u32 index;
229
230 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
231 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
232 return index + 1;
233
234 return 0;
235}
236
1b8fec13
TM
237#if defined(CONFIG_APM821XX)
238
239void get_sys_info(sys_info_t *sysInfo)
240{
241 unsigned long plld;
242 unsigned long temp;
243 unsigned long mul;
244 unsigned long cpudv;
245 unsigned long plb2dv;
246 unsigned long ddr2dv;
247
248 /* Calculate Forward divisor A and Feeback divisor */
249 mfcpr(CPR0_PLLD, plld);
250
251 temp = CPR0_PLLD_FWDVA(plld);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
253
254 temp = CPR0_PLLD_FDV(plld);
255 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
256
257 /* Calculate OPB clock divisor */
258 mfcpr(CPR0_OPBD, temp);
259 temp = CPR0_OPBD_OPBDV(temp);
260 sysInfo->pllOpbDiv = temp ? temp : 4;
261
262 /* Calculate Peripheral clock divisor */
263 mfcpr(CPR0_PERD, temp);
264 temp = CPR0_PERD_PERDV(temp);
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
266
267 /* Calculate CPU clock divisor */
268 mfcpr(CPR0_CPUD, temp);
269 temp = CPR0_CPUD_CPUDV(temp);
270 cpudv = temp ? temp : 8;
271
272 /* Calculate PLB2 clock divisor */
273 mfcpr(CPR0_PLB2D, temp);
274 temp = CPR0_PLB2D_PLB2DV(temp);
275 plb2dv = temp ? temp : 4;
276
277 /* Calculate DDR2 clock divisor */
278 mfcpr(CPR0_DDR2D, temp);
279 temp = CPR0_DDR2D_DDR2DV(temp);
280 ddr2dv = temp ? temp : 4;
281
282 /* Calculate 'M' based on feedback source */
283 mfcpr(CPR0_PLLC, temp);
284 temp = CPR0_PLLC_SEL(temp);
285 if (temp == 0) {
286 /* PLL internal feedback */
287 mul = sysInfo->pllFbkDiv;
288 } else {
289 /* PLL PerClk feedback */
290 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
291 * plb2dv * 2 * sysInfo->pllOpbDiv *
292 sysInfo->pllExtBusDiv;
293 }
294
295 /* Now calculate the individual clocks */
296 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
297 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
298 sysInfo->pllFwdDivA / cpudv;
299 sysInfo->freqPLB = sysInfo->freqVCOMhz /
300 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
301 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
302 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
303 sysInfo->freqDDR = sysInfo->freqVCOMhz /
304 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
305 sysInfo->freqUART = sysInfo->freqPLB;
306}
307
308#else
2801b2d2
SR
309/*
310 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
311 * with latest EAS
312 */
313void get_sys_info (sys_info_t * sysInfo)
314{
315 unsigned long strp0;
316 unsigned long strp1;
317 unsigned long temp;
318 unsigned long m;
319 unsigned long plbedv0;
320
321 /* Extract configured divisors */
d1c3b275
SR
322 mfsdr(SDR0_SDSTP0, strp0);
323 mfsdr(SDR0_SDSTP1, strp1);
2801b2d2
SR
324
325 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
326 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
327
328 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
329 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
330
331 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
332 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
333
334 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
335 sysInfo->pllOpbDiv = temp ? temp : 4;
336
337 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
338 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
339 sysInfo->pllExtBusDiv = temp ? temp : 4;
340
341 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
342 plbedv0 = temp ? temp: 8;
343
344 /* Calculate 'M' based on feedback source */
345 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
346 if (temp == 0) {
347 /* PLL internal feedback */
348 m = sysInfo->pllFbkDiv;
349 } else {
350 /* PLL PerClk feedback */
351 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
352 sysInfo->pllExtBusDiv;
353 }
354
355 /* Now calculate the individual clocks */
356 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
357 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
358 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
359 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
360 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
361 sysInfo->freqDDR = sysInfo->freqPLB;
362 sysInfo->freqUART = sysInfo->freqPLB;
363
364 return;
365}
1b8fec13 366#endif
2801b2d2
SR
367
368#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
887e2ec9 369 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
c157d8e2
SR
370void get_sys_info (sys_info_t *sysInfo)
371{
372 unsigned long temp;
373 unsigned long reg;
374 unsigned long lfdiv;
375 unsigned long m;
376 unsigned long prbdv0;
377 /*
378 WARNING: ASSUMES the following:
379 ENG=1
380 PRADV0=1
381 PRBDV0=1
382 */
383
384 /* Decode CPR0_PLLD0 for divisors */
d1c3b275 385 mfcpr(CPR0_PLLD, reg);
c157d8e2
SR
386 temp = (reg & PLLD_FWDVA_MASK) >> 16;
387 sysInfo->pllFwdDivA = temp ? temp : 16;
388 temp = (reg & PLLD_FWDVB_MASK) >> 8;
389 sysInfo->pllFwdDivB = temp ? temp: 8 ;
390 temp = (reg & PLLD_FBDV_MASK) >> 24;
391 sysInfo->pllFbkDiv = temp ? temp : 32;
392 lfdiv = reg & PLLD_LFBDV_MASK;
393
ddc922ff 394 mfcpr(CPR0_OPBD0, reg);
c157d8e2
SR
395 temp = (reg & OPBDDV_MASK) >> 24;
396 sysInfo->pllOpbDiv = temp ? temp : 4;
397
d1c3b275 398 mfcpr(CPR0_PERD, reg);
c157d8e2
SR
399 temp = (reg & PERDV_MASK) >> 24;
400 sysInfo->pllExtBusDiv = temp ? temp : 8;
401
ddc922ff 402 mfcpr(CPR0_PRIMBD0, reg);
c157d8e2
SR
403 temp = (reg & PRBDV_MASK) >> 24;
404 prbdv0 = temp ? temp : 8;
405
d1c3b275 406 mfcpr(CPR0_SPCID, reg);
c157d8e2
SR
407 temp = (reg & SPCID_MASK) >> 24;
408 sysInfo->pllPciDiv = temp ? temp : 4;
409
410 /* Calculate 'M' based on feedback source */
d1c3b275 411 mfsdr(SDR0_SDSTP0, reg);
c157d8e2
SR
412 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
413 if (temp == 0) { /* PLL output */
414 /* Figure which pll to use */
d1c3b275 415 mfcpr(CPR0_PLLC, reg);
c157d8e2
SR
416 temp = (reg & PLLC_SRC_MASK) >> 29;
417 if (!temp) /* PLLOUTA */
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
419 else /* PLLOUTB */
420 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
421 }
422 else if (temp == 1) /* CPU output */
423 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
424 else /* PerClk */
425 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
426
427 /* Now calculate the individual clocks */
428 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
429 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
430 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
431 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
dbbd1257 432 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
c157d8e2 433 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
fa8aea20 434 sysInfo->freqUART = sysInfo->freqPLB;
c157d8e2
SR
435
436 /* Figure which timer source to use */
58ea142f
MF
437 if (mfspr(SPRN_CCR1) & 0x0080) {
438 /* External Clock, assume same as SYS_CLK */
c157d8e2
SR
439 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
440 if (CONFIG_SYS_CLK_FREQ > temp)
441 sysInfo->freqTmrClk = temp;
442 else
443 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
444 }
445 else /* Internal clock */
446 sysInfo->freqTmrClk = sysInfo->freqProcessor;
447}
fa8aea20 448
c157d8e2
SR
449/********************************************
450 * get_PCI_freq
451 * return PCI bus freq in Hz
452 *********************************************/
453ulong get_PCI_freq (void)
454{
455 sys_info_t sys_info;
456 get_sys_info (&sys_info);
457 return sys_info.freqPCI;
458}
459
d865fd09
RR
460#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
461 && !defined(CONFIG_XILINX_440)
c609719b
WD
462void get_sys_info (sys_info_t * sysInfo)
463{
464 unsigned long strp0;
465 unsigned long temp;
466 unsigned long m;
467
468 /* Extract configured divisors */
d1c3b275 469 strp0 = mfdcr( CPC0_STRP0 );
c609719b
WD
470 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
471 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
472 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
473 sysInfo->pllFbkDiv = temp ? temp : 16;
474 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
475 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
476
477 /* Calculate 'M' based on feedback source */
478 if( strp0 & PLLSYS0_EXTSL_MASK )
479 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
480 else
481 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
482
483 /* Now calculate the individual clocks */
484 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
485 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
486 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
c157d8e2
SR
487 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
488 sysInfo->freqPLB >>= 1;
c609719b 489 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
dbbd1257 490 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
fa8aea20 491 sysInfo->freqUART = sysInfo->freqPLB;
c609719b 492}
ba56f625 493#else
d865fd09
RR
494
495#if !defined(CONFIG_XILINX_440)
ba56f625
WD
496void get_sys_info (sys_info_t * sysInfo)
497{
498 unsigned long strp0;
499 unsigned long strp1;
500 unsigned long temp;
501 unsigned long temp1;
502 unsigned long lfdiv;
503 unsigned long m;
42dfe7a1 504 unsigned long prbdv0;
ba56f625 505
4745acaa 506#if defined(CONFIG_YUCCA)
6c5879f3
MB
507 unsigned long sys_freq;
508 unsigned long sys_per=0;
509 unsigned long msr;
510 unsigned long pci_clock_per;
511 unsigned long sdr_ddrpll;
512
513 /*-------------------------------------------------------------------------+
514 | Get the system clock period.
515 +-------------------------------------------------------------------------*/
516 sys_per = determine_sysper();
517
518 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
519
520 /*-------------------------------------------------------------------------+
521 | Calculate the system clock speed from the period.
522 +-------------------------------------------------------------------------*/
4745acaa 523 sys_freq = (ONE_BILLION / sys_per) * 1000;
6c5879f3
MB
524#endif
525
ba56f625 526 /* Extract configured divisors */
d1c3b275
SR
527 mfsdr( SDR0_SDSTP0,strp0 );
528 mfsdr( SDR0_SDSTP1,strp1 );
ba56f625
WD
529
530 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
531 sysInfo->pllFwdDivA = temp ? temp : 16 ;
532 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
533 sysInfo->pllFwdDivB = temp ? temp: 8 ;
534 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
535 sysInfo->pllFbkDiv = temp ? temp : 32;
536 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
537 sysInfo->pllOpbDiv = temp ? temp : 4;
538 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
539 sysInfo->pllExtBusDiv = temp ? temp : 4;
0e6d798c 540 prbdv0 = (strp0 >> 2) & 0x7;
ba56f625
WD
541
542 /* Calculate 'M' based on feedback source */
543 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
544 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
545 lfdiv = temp1 ? temp1 : 64;
546 if (temp == 0) { /* PLL output */
547 /* Figure which pll to use */
548 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
549 if (!temp)
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
551 else
552 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
553 }
554 else if (temp == 1) /* CPU output */
555 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
556 else /* PerClk */
557 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
558
559 /* Now calculate the individual clocks */
4745acaa 560#if defined(CONFIG_YUCCA)
6c5879f3
MB
561 sysInfo->freqVCOMhz = (m * sys_freq) ;
562#else
4745acaa 563 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
6c5879f3 564#endif
ba56f625 565 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
0e6d798c 566 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
ba56f625 567 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
dbbd1257 568 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
ba56f625 569
4745acaa 570#if defined(CONFIG_YUCCA)
6c5879f3
MB
571 /* Determine PCI Clock Period */
572 pci_clock_per = determine_pci_clock_per();
573 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
d1c3b275 574 mfsdr(SDR0_DDR0, sdr_ddrpll);
6c5879f3
MB
575 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
576#endif
577
fa8aea20 578 sysInfo->freqUART = sysInfo->freqPLB;
6c5879f3
MB
579}
580
581#endif
d865fd09 582#endif /* CONFIG_XILINX_440 */
6c5879f3 583
4745acaa 584#if defined(CONFIG_YUCCA)
6c5879f3
MB
585unsigned long determine_sysper(void)
586{
587 unsigned int fpga_clocking_reg;
588 unsigned int master_clock_selection;
589 unsigned long master_clock_per = 0;
590 unsigned long fb_div_selection;
591 unsigned int vco_div_reg_value;
592 unsigned long vco_div_selection;
593 unsigned long sys_per = 0;
594 int extClkVal;
595
596 /*-------------------------------------------------------------------------+
597 | Read FPGA reg 0 and reg 1 to get FPGA reg information
598 +-------------------------------------------------------------------------*/
599 fpga_clocking_reg = in16(FPGA_REG16);
600
601
602 /* Determine Master Clock Source Selection */
603 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
604
605 switch(master_clock_selection) {
606 case FPGA_REG16_MASTER_CLK_66_66:
607 master_clock_per = PERIOD_66_66MHZ;
608 break;
609 case FPGA_REG16_MASTER_CLK_50:
610 master_clock_per = PERIOD_50_00MHZ;
611 break;
612 case FPGA_REG16_MASTER_CLK_33_33:
613 master_clock_per = PERIOD_33_33MHZ;
614 break;
615 case FPGA_REG16_MASTER_CLK_25:
616 master_clock_per = PERIOD_25_00MHZ;
617 break;
618 case FPGA_REG16_MASTER_CLK_EXT:
619 if ((extClkVal==EXTCLK_33_33)
620 && (extClkVal==EXTCLK_50)
621 && (extClkVal==EXTCLK_66_66)
622 && (extClkVal==EXTCLK_83)) {
623 /* calculate master clock period from external clock value */
624 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
625 } else {
626 /* Unsupported */
627 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
628 hang();
629 }
630 break;
631 default:
632 /* Unsupported */
633 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
634 hang();
635 break;
636 }
637
638 /* Determine FB divisors values */
639 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
640 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
641 fb_div_selection = FPGA_FB_DIV_6;
642 else
643 fb_div_selection = FPGA_FB_DIV_12;
644 } else {
645 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
646 fb_div_selection = FPGA_FB_DIV_10;
647 else
648 fb_div_selection = FPGA_FB_DIV_20;
649 }
650
651 /* Determine VCO divisors values */
652 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
653
654 switch(vco_div_reg_value) {
655 case FPGA_REG16_VCO_DIV_4:
656 vco_div_selection = FPGA_VCO_DIV_4;
657 break;
658 case FPGA_REG16_VCO_DIV_6:
659 vco_div_selection = FPGA_VCO_DIV_6;
660 break;
661 case FPGA_REG16_VCO_DIV_8:
662 vco_div_selection = FPGA_VCO_DIV_8;
663 break;
664 case FPGA_REG16_VCO_DIV_10:
665 default:
666 vco_div_selection = FPGA_VCO_DIV_10;
667 break;
668 }
669
670 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
671 switch(master_clock_per) {
672 case PERIOD_25_00MHZ:
673 if (fb_div_selection == FPGA_FB_DIV_12) {
674 if (vco_div_selection == FPGA_VCO_DIV_4)
675 sys_per = PERIOD_75_00MHZ;
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_50_00MHZ;
678 }
679 break;
680 case PERIOD_33_33MHZ:
681 if (fb_div_selection == FPGA_FB_DIV_6) {
682 if (vco_div_selection == FPGA_VCO_DIV_4)
683 sys_per = PERIOD_50_00MHZ;
684 if (vco_div_selection == FPGA_VCO_DIV_6)
685 sys_per = PERIOD_33_33MHZ;
686 }
687 if (fb_div_selection == FPGA_FB_DIV_10) {
688 if (vco_div_selection == FPGA_VCO_DIV_4)
689 sys_per = PERIOD_83_33MHZ;
690 if (vco_div_selection == FPGA_VCO_DIV_10)
691 sys_per = PERIOD_33_33MHZ;
692 }
693 if (fb_div_selection == FPGA_FB_DIV_12) {
694 if (vco_div_selection == FPGA_VCO_DIV_4)
695 sys_per = PERIOD_100_00MHZ;
696 if (vco_div_selection == FPGA_VCO_DIV_6)
697 sys_per = PERIOD_66_66MHZ;
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_50_00MHZ;
700 }
701 break;
702 case PERIOD_50_00MHZ:
703 if (fb_div_selection == FPGA_FB_DIV_6) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_75_00MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_6)
707 sys_per = PERIOD_50_00MHZ;
708 }
709 if (fb_div_selection == FPGA_FB_DIV_10) {
710 if (vco_div_selection == FPGA_VCO_DIV_6)
711 sys_per = PERIOD_83_33MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_10)
713 sys_per = PERIOD_50_00MHZ;
714 }
715 if (fb_div_selection == FPGA_FB_DIV_12) {
716 if (vco_div_selection == FPGA_VCO_DIV_6)
717 sys_per = PERIOD_100_00MHZ;
718 if (vco_div_selection == FPGA_VCO_DIV_8)
719 sys_per = PERIOD_75_00MHZ;
720 }
721 break;
722 case PERIOD_66_66MHZ:
723 if (fb_div_selection == FPGA_FB_DIV_6) {
724 if (vco_div_selection == FPGA_VCO_DIV_4)
725 sys_per = PERIOD_100_00MHZ;
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_66_66MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_8)
729 sys_per = PERIOD_50_00MHZ;
730 }
731 if (fb_div_selection == FPGA_FB_DIV_10) {
732 if (vco_div_selection == FPGA_VCO_DIV_8)
733 sys_per = PERIOD_83_33MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_10)
735 sys_per = PERIOD_66_66MHZ;
736 }
737 if (fb_div_selection == FPGA_FB_DIV_12) {
738 if (vco_div_selection == FPGA_VCO_DIV_8)
739 sys_per = PERIOD_100_00MHZ;
740 }
741 break;
742 default:
743 break;
744 }
745
746 if (sys_per == 0) {
747 /* Other combinations are not supported */
748 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
749 hang();
750 }
751 } else {
752 /* calcul system clock without cheking */
753 /* if engineering option clock no check is selected */
754 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
755 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
756 }
757
758 return(sys_per);
6c5879f3
MB
759}
760
761/*-------------------------------------------------------------------------+
762| determine_pci_clock_per.
763+-------------------------------------------------------------------------*/
764unsigned long determine_pci_clock_per(void)
765{
766 unsigned long pci_clock_selection, pci_period;
767
768 /*-------------------------------------------------------------------------+
769 | Read FPGA reg 6 to get PCI 0 FPGA reg information
770 +-------------------------------------------------------------------------*/
771 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
772
773
774 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
775
776 switch (pci_clock_selection) {
777 case FPGA_REG16_PCI0_CLK_133_33:
778 pci_period = PERIOD_133_33MHZ;
779 break;
780 case FPGA_REG16_PCI0_CLK_100:
781 pci_period = PERIOD_100_00MHZ;
782 break;
783 case FPGA_REG16_PCI0_CLK_66_66:
784 pci_period = PERIOD_66_66MHZ;
785 break;
786 default:
787 pci_period = PERIOD_33_33MHZ;;
788 break;
789 }
790
791 return(pci_period);
ba56f625
WD
792}
793#endif
c609719b 794
9fea65a6 795#elif defined(CONFIG_XILINX_405)
028ab6b5
WD
796extern void get_sys_info (sys_info_t * sysInfo);
797extern ulong get_PCI_freq (void);
798
c609719b
WD
799#elif defined(CONFIG_405)
800
fa8aea20
SR
801void get_sys_info (sys_info_t * sysInfo)
802{
c609719b
WD
803 sysInfo->freqVCOMhz=3125000;
804 sysInfo->freqProcessor=12*1000*1000;
805 sysInfo->freqPLB=50*1000*1000;
806 sysInfo->freqPCI=66*1000*1000;
c609719b
WD
807}
808
b867d705 809#elif defined(CONFIG_405EP)
087dfdb7 810void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
b867d705
SR
811{
812 unsigned long pllmr0;
813 unsigned long pllmr1;
814 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
815 unsigned long m;
816 unsigned long pllmr0_ccdv;
817
818 /*
819 * Read PLL Mode registers
820 */
d1c3b275
SR
821 pllmr0 = mfdcr (CPC0_PLLMR0);
822 pllmr1 = mfdcr (CPC0_PLLMR1);
b867d705
SR
823
824 /*
825 * Determine forward divider A
826 */
827 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
828
829 /*
830 * Determine forward divider B (should be equal to A)
831 */
832 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
833
834 /*
835 * Determine FBK_DIV.
836 */
837 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
fa8aea20 838 if (sysInfo->pllFbkDiv == 0)
b867d705 839 sysInfo->pllFbkDiv = 16;
b867d705
SR
840
841 /*
842 * Determine PLB_DIV.
843 */
844 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
845
846 /*
847 * Determine PCI_DIV.
848 */
849 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
850
851 /*
852 * Determine EXTBUS_DIV.
853 */
854 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
855
856 /*
857 * Determine OPB_DIV.
858 */
859 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
860
861 /*
862 * Determine the M factor
863 */
864 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
865
866 /*
867 * Determine VCO clock frequency
868 */
b39392a9
SR
869 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
870 (unsigned long long)sysClkPeriodPs;
b867d705
SR
871
872 /*
873 * Determine CPU clock frequency
874 */
875 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
876 if (pllmr1 & PLLMR1_SSCS_MASK) {
e55ca7e2
WD
877 /*
878 * This is true if FWDVA == FWDVB:
879 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
880 * / pllmr0_ccdv;
881 */
882 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
883 / sysInfo->pllFwdDiv / pllmr0_ccdv;
b867d705
SR
884 } else {
885 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
886 }
887
888 /*
889 * Determine PLB clock frequency
890 */
891 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
dbbd1257
SR
892
893 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
fa8aea20 894
9b1b8c8a
DE
895 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
896
fa8aea20 897 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
b867d705
SR
898}
899
900
b867d705
SR
901/********************************************
902 * get_PCI_freq
903 * return PCI bus freq in Hz
904 *********************************************/
905ulong get_PCI_freq (void)
906{
907 ulong val;
087dfdb7 908 PPC4xx_SYS_INFO sys_info;
b867d705
SR
909
910 get_sys_info (&sys_info);
911 val = sys_info.freqPLB / sys_info.pllPciDiv;
912 return val;
913}
914
e01bd218 915#elif defined(CONFIG_405EZ)
087dfdb7 916void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
e01bd218
SR
917{
918 unsigned long cpr_plld;
273db7e1 919 unsigned long cpr_pllc;
e01bd218
SR
920 unsigned long cpr_primad;
921 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
922 unsigned long primad_cpudv;
923 unsigned long m;
95a4a593 924 unsigned long plloutb;
e01bd218
SR
925
926 /*
927 * Read PLL Mode registers
928 */
d1c3b275
SR
929 mfcpr(CPR0_PLLD, cpr_plld);
930 mfcpr(CPR0_PLLC, cpr_pllc);
e01bd218
SR
931
932 /*
933 * Determine forward divider A
934 */
935 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
936
937 /*
273db7e1 938 * Determine forward divider B
e01bd218
SR
939 */
940 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
273db7e1 941 if (sysInfo->pllFwdDivB == 0)
e01bd218 942 sysInfo->pllFwdDivB = 8;
e01bd218
SR
943
944 /*
945 * Determine FBK_DIV.
946 */
947 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
273db7e1 948 if (sysInfo->pllFbkDiv == 0)
e01bd218 949 sysInfo->pllFbkDiv = 256;
e01bd218
SR
950
951 /*
952 * Read CPR_PRIMAD register
953 */
afabb498 954 mfcpr(CPR0_PRIMAD, cpr_primad);
fa8aea20 955
e01bd218
SR
956 /*
957 * Determine PLB_DIV.
958 */
959 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
273db7e1 960 if (sysInfo->pllPlbDiv == 0)
e01bd218 961 sysInfo->pllPlbDiv = 16;
e01bd218
SR
962
963 /*
964 * Determine EXTBUS_DIV.
965 */
966 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
273db7e1 967 if (sysInfo->pllExtBusDiv == 0)
e01bd218 968 sysInfo->pllExtBusDiv = 16;
e01bd218
SR
969
970 /*
971 * Determine OPB_DIV.
972 */
973 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
273db7e1 974 if (sysInfo->pllOpbDiv == 0)
e01bd218 975 sysInfo->pllOpbDiv = 16;
e01bd218
SR
976
977 /*
978 * Determine the M factor
979 */
273db7e1
SR
980 if (cpr_pllc & PLLC_SRC_MASK)
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
982 else
983 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
e01bd218
SR
984
985 /*
986 * Determine VCO clock frequency
987 */
988 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
989 (unsigned long long)sysClkPeriodPs;
990
991 /*
992 * Determine CPU clock frequency
993 */
994 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
273db7e1 995 if (primad_cpudv == 0)
e01bd218 996 primad_cpudv = 16;
e01bd218 997
273db7e1
SR
998 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
999 sysInfo->pllFwdDiv / primad_cpudv;
e01bd218
SR
1000
1001 /*
1002 * Determine PLB clock frequency
1003 */
273db7e1
SR
1004 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1005 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
dbbd1257 1006
e67af44d
SR
1007 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1008 sysInfo->pllOpbDiv;
1009
dbbd1257
SR
1010 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1011 sysInfo->pllExtBusDiv;
fa8aea20 1012
95a4a593
SR
1013 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1014 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1015 sysInfo->pllFwdDivB);
1016 sysInfo->freqUART = plloutb;
e01bd218
SR
1017}
1018
dbbd1257
SR
1019#elif defined(CONFIG_405EX)
1020
1021/*
1022 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1023 * We need the specs!!!!
1024 */
1025static unsigned char get_fbdv(unsigned char index)
1026{
1027 unsigned char ret = 0;
1028 /* This is table should be 256 bytes.
1029 * Only take first 52 values.
1030 */
1031 unsigned char fbdv_tb[] = {
1032 0x00, 0xff, 0x7f, 0xfd,
1033 0x7a, 0xf5, 0x6a, 0xd5,
1034 0x2a, 0xd4, 0x29, 0xd3,
1035 0x26, 0xcc, 0x19, 0xb3,
1036 0x67, 0xce, 0x1d, 0xbb,
1037 0x77, 0xee, 0x5d, 0xba,
1038 0x74, 0xe9, 0x52, 0xa5,
1039 0x4b, 0x96, 0x2c, 0xd8,
1040 0x31, 0xe3, 0x46, 0x8d,
1041 0x1b, 0xb7, 0x6f, 0xde,
1042 0x3d, 0xfb, 0x76, 0xed,
1043 0x5a, 0xb5, 0x6b, 0xd6,
1044 0x2d, 0xdb, 0x36, 0xec,
1045
1046 };
1047
1048 if ((index & 0x7f) == 0)
1049 return 1;
1050 while (ret < sizeof (fbdv_tb)) {
1051 if (fbdv_tb[ret] == index)
1052 break;
1053 ret++;
1054 }
1055 ret++;
1056
1057 return ret;
1058}
1059
1060#define PLL_FBK_PLL_LOCAL 0
1061#define PLL_FBK_CPU 1
1062#define PLL_FBK_PERCLK 5
1063
1064void get_sys_info (sys_info_t * sysInfo)
1065{
1066 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1067 unsigned long m = 1;
1068 unsigned int tmp;
1069 unsigned char fwdva[16] = {
1070 1, 2, 14, 9, 4, 11, 16, 13,
1071 12, 5, 6, 15, 10, 7, 8, 3,
1072 };
1073 unsigned char sel, cpudv0, plb2xDiv;
1074
d1c3b275 1075 mfcpr(CPR0_PLLD, tmp);
dbbd1257
SR
1076
1077 /*
1078 * Determine forward divider A
1079 */
1080 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1081
1082 /*
1083 * Determine FBK_DIV.
1084 */
1085 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1086
1087 /*
1088 * Determine PLBDV0
1089 */
1090 sysInfo->pllPlbDiv = 2;
1091
1092 /*
1093 * Determine PERDV0
1094 */
d1c3b275 1095 mfcpr(CPR0_PERD, tmp);
dbbd1257
SR
1096 tmp = (tmp >> 24) & 0x03;
1097 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1098
1099 /*
1100 * Determine OPBDV0
1101 */
ddc922ff 1102 mfcpr(CPR0_OPBD0, tmp);
dbbd1257
SR
1103 tmp = (tmp >> 24) & 0x03;
1104 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1105
1106 /* Determine PLB2XDV0 */
d1c3b275 1107 mfcpr(CPR0_PLBD, tmp);
dbbd1257
SR
1108 tmp = (tmp >> 16) & 0x07;
1109 plb2xDiv = (tmp == 0) ? 8 : tmp;
1110
1111 /* Determine CPUDV0 */
d1c3b275 1112 mfcpr(CPR0_CPUD, tmp);
dbbd1257
SR
1113 tmp = (tmp >> 24) & 0x07;
1114 cpudv0 = (tmp == 0) ? 8 : tmp;
1115
1116 /* Determine SEL(5:7) in CPR0_PLLC */
d1c3b275 1117 mfcpr(CPR0_PLLC, tmp);
dbbd1257
SR
1118 sel = (tmp >> 24) & 0x07;
1119
1120 /*
1121 * Determine the M factor
1122 * PLL local: M = FBDV
1123 * CPU clock: M = FBDV * FWDVA * CPUDV0
1124 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1125 *
1126 */
1127 switch (sel) {
1128 case PLL_FBK_CPU:
1129 m = sysInfo->pllFwdDiv * cpudv0;
1130 break;
1131 case PLL_FBK_PERCLK:
1132 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1133 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1134 break;
53677ef1 1135 case PLL_FBK_PLL_LOCAL:
dbbd1257
SR
1136 break;
1137 default:
1138 printf("%s unknown m\n", __FUNCTION__);
1139 return;
1140
1141 }
1142 m *= sysInfo->pllFbkDiv;
1143
1144 /*
1145 * Determine VCO clock frequency
1146 */
1147 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1148 (unsigned long long)sysClkPeriodPs;
1149
1150 /*
1151 * Determine CPU clock frequency
1152 */
1153 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1154
1155 /*
1156 * Determine PLB clock frequency, ddr1x should be the same
1157 */
1158 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1159 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1160 sysInfo->freqDDR = sysInfo->freqPLB;
1161 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
fa8aea20 1162 sysInfo->freqUART = sysInfo->freqPLB;
dbbd1257
SR
1163}
1164
c609719b
WD
1165#endif
1166
1167int get_clocks (void)
1168{
c609719b
WD
1169 sys_info_t sys_info;
1170
1171 get_sys_info (&sys_info);
1172 gd->cpu_clk = sys_info.freqProcessor;
1173 gd->bus_clk = sys_info.freqPLB;
1174
c609719b
WD
1175 return (0);
1176}
1177
1178
1179/********************************************
1180 * get_bus_freq
1181 * return PLB bus freq in Hz
1182 *********************************************/
1183ulong get_bus_freq (ulong dummy)
1184{
1185 ulong val;
1186
e01bd218
SR
1187#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
dbbd1257
SR
1189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1190 defined(CONFIG_440)
c609719b
WD
1191 sys_info_t sys_info;
1192
1193 get_sys_info (&sys_info);
1194 val = sys_info.freqPLB;
c609719b
WD
1195#else
1196# error get_bus_freq() not implemented
1197#endif
1198
1199 return val;
1200}
e67af44d 1201
e67af44d
SR
1202ulong get_OPB_freq (void)
1203{
1204 PPC4xx_SYS_INFO sys_info;
1205
1206 get_sys_info (&sys_info);
1207
1208 return sys_info.freqOPB;
1209}