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