]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/powerpc/cpu/ppc4xx/speed.c
Merge branch 'master' of git://git.denx.de/u-boot-blackfin
[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_AP1000)
816 void get_sys_info (sys_info_t * sysInfo)
817 {
818         sysInfo->freqProcessor = 240 * 1000 * 1000;
819         sysInfo->freqPLB = 80 * 1000 * 1000;
820         sysInfo->freqPCI = 33 * 1000 * 1000;
821 }
822
823 #elif defined(CONFIG_405)
824
825 void get_sys_info (sys_info_t * sysInfo)
826 {
827         sysInfo->freqVCOMhz=3125000;
828         sysInfo->freqProcessor=12*1000*1000;
829         sysInfo->freqPLB=50*1000*1000;
830         sysInfo->freqPCI=66*1000*1000;
831 }
832
833 #elif defined(CONFIG_405EP)
834 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
835 {
836         unsigned long pllmr0;
837         unsigned long pllmr1;
838         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
839         unsigned long m;
840         unsigned long pllmr0_ccdv;
841
842         /*
843          * Read PLL Mode registers
844          */
845         pllmr0 = mfdcr (CPC0_PLLMR0);
846         pllmr1 = mfdcr (CPC0_PLLMR1);
847
848         /*
849          * Determine forward divider A
850          */
851         sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
852
853         /*
854          * Determine forward divider B (should be equal to A)
855          */
856         sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
857
858         /*
859          * Determine FBK_DIV.
860          */
861         sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
862         if (sysInfo->pllFbkDiv == 0)
863                 sysInfo->pllFbkDiv = 16;
864
865         /*
866          * Determine PLB_DIV.
867          */
868         sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
869
870         /*
871          * Determine PCI_DIV.
872          */
873         sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
874
875         /*
876          * Determine EXTBUS_DIV.
877          */
878         sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
879
880         /*
881          * Determine OPB_DIV.
882          */
883         sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
884
885         /*
886          * Determine the M factor
887          */
888         m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
889
890         /*
891          * Determine VCO clock frequency
892          */
893         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
894                 (unsigned long long)sysClkPeriodPs;
895
896         /*
897          * Determine CPU clock frequency
898          */
899         pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
900         if (pllmr1 & PLLMR1_SSCS_MASK) {
901                 /*
902                  * This is true if FWDVA == FWDVB:
903                  * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
904                  *      / pllmr0_ccdv;
905                  */
906                 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
907                         / sysInfo->pllFwdDiv / pllmr0_ccdv;
908         } else {
909                 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
910         }
911
912         /*
913          * Determine PLB clock frequency
914          */
915         sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
916
917         sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
918
919         sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
920
921         sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
922 }
923
924
925 /********************************************
926  * get_PCI_freq
927  * return PCI bus freq in Hz
928  *********************************************/
929 ulong get_PCI_freq (void)
930 {
931         ulong val;
932         PPC4xx_SYS_INFO sys_info;
933
934         get_sys_info (&sys_info);
935         val = sys_info.freqPLB / sys_info.pllPciDiv;
936         return val;
937 }
938
939 #elif defined(CONFIG_405EZ)
940 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
941 {
942         unsigned long cpr_plld;
943         unsigned long cpr_pllc;
944         unsigned long cpr_primad;
945         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
946         unsigned long primad_cpudv;
947         unsigned long m;
948         unsigned long plloutb;
949
950         /*
951          * Read PLL Mode registers
952          */
953         mfcpr(CPR0_PLLD, cpr_plld);
954         mfcpr(CPR0_PLLC, cpr_pllc);
955
956         /*
957          * Determine forward divider A
958          */
959         sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
960
961         /*
962          * Determine forward divider B
963          */
964         sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
965         if (sysInfo->pllFwdDivB == 0)
966                 sysInfo->pllFwdDivB = 8;
967
968         /*
969          * Determine FBK_DIV.
970          */
971         sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
972         if (sysInfo->pllFbkDiv == 0)
973                 sysInfo->pllFbkDiv = 256;
974
975         /*
976          * Read CPR_PRIMAD register
977          */
978         mfcpr(CPR0_PRIMAD, cpr_primad);
979
980         /*
981          * Determine PLB_DIV.
982          */
983         sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
984         if (sysInfo->pllPlbDiv == 0)
985                 sysInfo->pllPlbDiv = 16;
986
987         /*
988          * Determine EXTBUS_DIV.
989          */
990         sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
991         if (sysInfo->pllExtBusDiv == 0)
992                 sysInfo->pllExtBusDiv = 16;
993
994         /*
995          * Determine OPB_DIV.
996          */
997         sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
998         if (sysInfo->pllOpbDiv == 0)
999                 sysInfo->pllOpbDiv = 16;
1000
1001         /*
1002          * Determine the M factor
1003          */
1004         if (cpr_pllc & PLLC_SRC_MASK)
1005                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
1006         else
1007                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
1008
1009         /*
1010          * Determine VCO clock frequency
1011          */
1012         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1013                 (unsigned long long)sysClkPeriodPs;
1014
1015         /*
1016          * Determine CPU clock frequency
1017          */
1018         primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
1019         if (primad_cpudv == 0)
1020                 primad_cpudv = 16;
1021
1022         sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1023                 sysInfo->pllFwdDiv / primad_cpudv;
1024
1025         /*
1026          * Determine PLB clock frequency
1027          */
1028         sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1029                 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1030
1031         sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1032                 sysInfo->pllOpbDiv;
1033
1034         sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1035                 sysInfo->pllExtBusDiv;
1036
1037         plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1038                 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1039                 sysInfo->pllFwdDivB);
1040         sysInfo->freqUART = plloutb;
1041 }
1042
1043 #elif defined(CONFIG_405EX)
1044
1045 /*
1046  * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1047  *   We need the specs!!!!
1048  */
1049 static unsigned char get_fbdv(unsigned char index)
1050 {
1051         unsigned char ret = 0;
1052         /* This is table should be 256 bytes.
1053          * Only take first 52 values.
1054          */
1055         unsigned char fbdv_tb[] = {
1056                 0x00, 0xff, 0x7f, 0xfd,
1057                 0x7a, 0xf5, 0x6a, 0xd5,
1058                 0x2a, 0xd4, 0x29, 0xd3,
1059                 0x26, 0xcc, 0x19, 0xb3,
1060                 0x67, 0xce, 0x1d, 0xbb,
1061                 0x77, 0xee, 0x5d, 0xba,
1062                 0x74, 0xe9, 0x52, 0xa5,
1063                 0x4b, 0x96, 0x2c, 0xd8,
1064                 0x31, 0xe3, 0x46, 0x8d,
1065                 0x1b, 0xb7, 0x6f, 0xde,
1066                 0x3d, 0xfb, 0x76, 0xed,
1067                 0x5a, 0xb5, 0x6b, 0xd6,
1068                 0x2d, 0xdb, 0x36, 0xec,
1069
1070         };
1071
1072         if ((index & 0x7f) == 0)
1073                 return 1;
1074         while (ret < sizeof (fbdv_tb)) {
1075                 if (fbdv_tb[ret] == index)
1076                         break;
1077                 ret++;
1078         }
1079         ret++;
1080
1081         return ret;
1082 }
1083
1084 #define PLL_FBK_PLL_LOCAL       0
1085 #define PLL_FBK_CPU             1
1086 #define PLL_FBK_PERCLK          5
1087
1088 void get_sys_info (sys_info_t * sysInfo)
1089 {
1090         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1091         unsigned long m = 1;
1092         unsigned int  tmp;
1093         unsigned char fwdva[16] = {
1094                 1, 2, 14, 9, 4, 11, 16, 13,
1095                 12, 5, 6, 15, 10, 7, 8, 3,
1096         };
1097         unsigned char sel, cpudv0, plb2xDiv;
1098
1099         mfcpr(CPR0_PLLD, tmp);
1100
1101         /*
1102          * Determine forward divider A
1103          */
1104         sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];       /* FWDVA */
1105
1106         /*
1107          * Determine FBK_DIV.
1108          */
1109         sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1110
1111         /*
1112          * Determine PLBDV0
1113          */
1114         sysInfo->pllPlbDiv = 2;
1115
1116         /*
1117          * Determine PERDV0
1118          */
1119         mfcpr(CPR0_PERD, tmp);
1120         tmp = (tmp >> 24) & 0x03;
1121         sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1122
1123         /*
1124          * Determine OPBDV0
1125          */
1126         mfcpr(CPR0_OPBD0, tmp);
1127         tmp = (tmp >> 24) & 0x03;
1128         sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1129
1130         /* Determine PLB2XDV0 */
1131         mfcpr(CPR0_PLBD, tmp);
1132         tmp = (tmp >> 16) & 0x07;
1133         plb2xDiv = (tmp == 0) ? 8 : tmp;
1134
1135         /* Determine CPUDV0 */
1136         mfcpr(CPR0_CPUD, tmp);
1137         tmp = (tmp >> 24) & 0x07;
1138         cpudv0 = (tmp == 0) ? 8 : tmp;
1139
1140         /* Determine SEL(5:7) in CPR0_PLLC */
1141         mfcpr(CPR0_PLLC, tmp);
1142         sel = (tmp >> 24) & 0x07;
1143
1144         /*
1145          * Determine the M factor
1146          * PLL local: M = FBDV
1147          * CPU clock: M = FBDV * FWDVA * CPUDV0
1148          * PerClk       : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1149          *
1150          */
1151         switch (sel) {
1152         case PLL_FBK_CPU:
1153                 m = sysInfo->pllFwdDiv * cpudv0;
1154                 break;
1155         case PLL_FBK_PERCLK:
1156                 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1157                         * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1158                 break;
1159         case PLL_FBK_PLL_LOCAL:
1160                 break;
1161         default:
1162                 printf("%s unknown m\n", __FUNCTION__);
1163                 return;
1164
1165         }
1166         m *= sysInfo->pllFbkDiv;
1167
1168         /*
1169          * Determine VCO clock frequency
1170          */
1171         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1172                 (unsigned long long)sysClkPeriodPs;
1173
1174         /*
1175          * Determine CPU clock frequency
1176          */
1177         sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1178
1179         /*
1180          * Determine PLB clock frequency, ddr1x should be the same
1181          */
1182         sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1183         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1184         sysInfo->freqDDR = sysInfo->freqPLB;
1185         sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1186         sysInfo->freqUART = sysInfo->freqPLB;
1187 }
1188
1189 #endif
1190
1191 int get_clocks (void)
1192 {
1193 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1194     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1195     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1196     defined(CONFIG_440)
1197         sys_info_t sys_info;
1198
1199         get_sys_info (&sys_info);
1200         gd->cpu_clk = sys_info.freqProcessor;
1201         gd->bus_clk = sys_info.freqPLB;
1202
1203 #endif  /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1204
1205 #ifdef CONFIG_IOP480
1206         gd->cpu_clk = 66000000;
1207         gd->bus_clk = 66000000;
1208 #endif
1209         return (0);
1210 }
1211
1212
1213 /********************************************
1214  * get_bus_freq
1215  * return PLB bus freq in Hz
1216  *********************************************/
1217 ulong get_bus_freq (ulong dummy)
1218 {
1219         ulong val;
1220
1221 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1222     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1223     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1224     defined(CONFIG_440)
1225         sys_info_t sys_info;
1226
1227         get_sys_info (&sys_info);
1228         val = sys_info.freqPLB;
1229
1230 #elif defined(CONFIG_IOP480)
1231
1232         val = 66;
1233
1234 #else
1235 # error get_bus_freq() not implemented
1236 #endif
1237
1238         return val;
1239 }
1240
1241 #if !defined(CONFIG_IOP480)
1242 ulong get_OPB_freq (void)
1243 {
1244         PPC4xx_SYS_INFO sys_info;
1245
1246         get_sys_info (&sys_info);
1247
1248         return sys_info.freqOPB;
1249 }
1250 #endif