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