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