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