Merge branch 'master' of /home/stefan/git/u-boot/u-boot into next
[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 (pllmd);
54
55         /*
56          * Read Pin Strapping register
57          */
58         psr = mfdcr (strap);
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(sdr_sdstp0, strp0);
284         mfsdr(sdr_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(clk_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(clk_opbd, reg);
355         temp = (reg & OPBDDV_MASK) >> 24;
356         sysInfo->pllOpbDiv = temp ? temp : 4;
357
358         mfcpr(clk_perd, reg);
359         temp = (reg & PERDV_MASK) >> 24;
360         sysInfo->pllExtBusDiv = temp ? temp : 8;
361
362         mfcpr(clk_primbd, reg);
363         temp = (reg & PRBDV_MASK) >> 24;
364         prbdv0 = temp ? temp : 8;
365
366         mfcpr(clk_spcid, reg);
367         temp = (reg & SPCID_MASK) >> 24;
368         sysInfo->pllPciDiv = temp ? temp : 4;
369
370         /* Calculate 'M' based on feedback source */
371         mfsdr(sdr_sdstp0, reg);
372         temp = (reg & PLLSYS0_SEL_MASK) >> 27;
373         if (temp == 0) { /* PLL output */
374                 /* Figure which pll to use */
375                 mfcpr(clk_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(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
398                 temp = sysInfo->freqProcessor / 2;  /* Max extern clock speed */
399                 if (CONFIG_SYS_CLK_FREQ > temp)
400                         sysInfo->freqTmrClk = temp;
401                 else
402                         sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
403         }
404         else  /* Internal clock */
405                 sysInfo->freqTmrClk = sysInfo->freqProcessor;
406 }
407
408 /********************************************
409  * get_PCI_freq
410  * return PCI bus freq in Hz
411  *********************************************/
412 ulong get_PCI_freq (void)
413 {
414         sys_info_t sys_info;
415         get_sys_info (&sys_info);
416         return sys_info.freqPCI;
417 }
418
419 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
420 void get_sys_info (sys_info_t * sysInfo)
421 {
422         unsigned long strp0;
423         unsigned long temp;
424         unsigned long m;
425
426         /* Extract configured divisors */
427         strp0 = mfdcr( cpc0_strp0 );
428         sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
429         sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
430         temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
431         sysInfo->pllFbkDiv = temp ? temp : 16;
432         sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
433         sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
434
435         /* Calculate 'M' based on feedback source */
436         if( strp0 & PLLSYS0_EXTSL_MASK )
437                 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
438         else
439                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
440
441         /* Now calculate the individual clocks */
442         sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
443         sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
444         sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
445         if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
446                 sysInfo->freqPLB >>= 1;
447         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
448         sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
449         sysInfo->freqUART = sysInfo->freqPLB;
450 }
451 #else
452 void get_sys_info (sys_info_t * sysInfo)
453 {
454         unsigned long strp0;
455         unsigned long strp1;
456         unsigned long temp;
457         unsigned long temp1;
458         unsigned long lfdiv;
459         unsigned long m;
460         unsigned long prbdv0;
461
462 #if defined(CONFIG_YUCCA)
463         unsigned long sys_freq;
464         unsigned long sys_per=0;
465         unsigned long msr;
466         unsigned long pci_clock_per;
467         unsigned long sdr_ddrpll;
468
469         /*-------------------------------------------------------------------------+
470          | Get the system clock period.
471          +-------------------------------------------------------------------------*/
472         sys_per = determine_sysper();
473
474         msr = (mfmsr () & ~(MSR_EE));   /* disable interrupts */
475
476         /*-------------------------------------------------------------------------+
477          | Calculate the system clock speed from the period.
478          +-------------------------------------------------------------------------*/
479         sys_freq = (ONE_BILLION / sys_per) * 1000;
480 #endif
481
482         /* Extract configured divisors */
483         mfsdr( sdr_sdstp0,strp0 );
484         mfsdr( sdr_sdstp1,strp1 );
485
486         temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
487         sysInfo->pllFwdDivA = temp ? temp : 16 ;
488         temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
489         sysInfo->pllFwdDivB = temp ? temp: 8 ;
490         temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
491         sysInfo->pllFbkDiv = temp ? temp : 32;
492         temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
493         sysInfo->pllOpbDiv = temp ? temp : 4;
494         temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
495         sysInfo->pllExtBusDiv = temp ? temp : 4;
496         prbdv0 = (strp0 >> 2) & 0x7;
497
498         /* Calculate 'M' based on feedback source */
499         temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
500         temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
501         lfdiv = temp1 ? temp1 : 64;
502         if (temp == 0) { /* PLL output */
503                 /* Figure which pll to use */
504                 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
505                 if (!temp)
506                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
507                 else
508                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
509         }
510         else if (temp == 1) /* CPU output */
511                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
512         else /* PerClk */
513                 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
514
515         /* Now calculate the individual clocks */
516 #if defined(CONFIG_YUCCA)
517         sysInfo->freqVCOMhz = (m * sys_freq) ;
518 #else
519         sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
520 #endif
521         sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
522         sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
523         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
524         sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
525
526 #if defined(CONFIG_YUCCA)
527         /* Determine PCI Clock Period */
528         pci_clock_per = determine_pci_clock_per();
529         sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
530         mfsdr(sdr_ddr0, sdr_ddrpll);
531         sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
532 #endif
533
534         sysInfo->freqUART = sysInfo->freqPLB;
535 }
536
537 #endif
538
539 #if defined(CONFIG_YUCCA)
540 unsigned long determine_sysper(void)
541 {
542         unsigned int fpga_clocking_reg;
543         unsigned int master_clock_selection;
544         unsigned long master_clock_per = 0;
545         unsigned long fb_div_selection;
546         unsigned int vco_div_reg_value;
547         unsigned long vco_div_selection;
548         unsigned long sys_per = 0;
549         int extClkVal;
550
551         /*-------------------------------------------------------------------------+
552          | Read FPGA reg 0 and reg 1 to get FPGA reg information
553          +-------------------------------------------------------------------------*/
554         fpga_clocking_reg = in16(FPGA_REG16);
555
556
557         /* Determine Master Clock Source Selection */
558         master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
559
560         switch(master_clock_selection) {
561                 case FPGA_REG16_MASTER_CLK_66_66:
562                         master_clock_per = PERIOD_66_66MHZ;
563                         break;
564                 case FPGA_REG16_MASTER_CLK_50:
565                         master_clock_per = PERIOD_50_00MHZ;
566                         break;
567                 case FPGA_REG16_MASTER_CLK_33_33:
568                         master_clock_per = PERIOD_33_33MHZ;
569                         break;
570                 case FPGA_REG16_MASTER_CLK_25:
571                         master_clock_per = PERIOD_25_00MHZ;
572                         break;
573                 case FPGA_REG16_MASTER_CLK_EXT:
574                         if ((extClkVal==EXTCLK_33_33)
575                                         && (extClkVal==EXTCLK_50)
576                                         && (extClkVal==EXTCLK_66_66)
577                                         && (extClkVal==EXTCLK_83)) {
578                                 /* calculate master clock period from external clock value */
579                                 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
580                         } else {
581                                 /* Unsupported */
582                                 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
583                                 hang();
584                         }
585                         break;
586                 default:
587                         /* Unsupported */
588                         DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
589                         hang();
590                         break;
591         }
592
593         /* Determine FB divisors values */
594         if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
595                 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
596                         fb_div_selection = FPGA_FB_DIV_6;
597                 else
598                         fb_div_selection = FPGA_FB_DIV_12;
599         } else {
600                 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
601                         fb_div_selection = FPGA_FB_DIV_10;
602                 else
603                         fb_div_selection = FPGA_FB_DIV_20;
604         }
605
606         /* Determine VCO divisors values */
607         vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
608
609         switch(vco_div_reg_value) {
610                 case FPGA_REG16_VCO_DIV_4:
611                         vco_div_selection = FPGA_VCO_DIV_4;
612                         break;
613                 case FPGA_REG16_VCO_DIV_6:
614                         vco_div_selection = FPGA_VCO_DIV_6;
615                         break;
616                 case FPGA_REG16_VCO_DIV_8:
617                         vco_div_selection = FPGA_VCO_DIV_8;
618                         break;
619                 case FPGA_REG16_VCO_DIV_10:
620                 default:
621                         vco_div_selection = FPGA_VCO_DIV_10;
622                         break;
623         }
624
625         if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
626                 switch(master_clock_per) {
627                         case PERIOD_25_00MHZ:
628                                 if (fb_div_selection == FPGA_FB_DIV_12) {
629                                         if (vco_div_selection == FPGA_VCO_DIV_4)
630                                                 sys_per = PERIOD_75_00MHZ;
631                                         if (vco_div_selection == FPGA_VCO_DIV_6)
632                                                 sys_per = PERIOD_50_00MHZ;
633                                 }
634                                 break;
635                         case PERIOD_33_33MHZ:
636                                 if (fb_div_selection == FPGA_FB_DIV_6) {
637                                         if (vco_div_selection == FPGA_VCO_DIV_4)
638                                                 sys_per = PERIOD_50_00MHZ;
639                                         if (vco_div_selection == FPGA_VCO_DIV_6)
640                                                 sys_per = PERIOD_33_33MHZ;
641                                 }
642                                 if (fb_div_selection == FPGA_FB_DIV_10) {
643                                         if (vco_div_selection == FPGA_VCO_DIV_4)
644                                                 sys_per = PERIOD_83_33MHZ;
645                                         if (vco_div_selection == FPGA_VCO_DIV_10)
646                                                 sys_per = PERIOD_33_33MHZ;
647                                 }
648                                 if (fb_div_selection == FPGA_FB_DIV_12) {
649                                         if (vco_div_selection == FPGA_VCO_DIV_4)
650                                                 sys_per = PERIOD_100_00MHZ;
651                                         if (vco_div_selection == FPGA_VCO_DIV_6)
652                                                 sys_per = PERIOD_66_66MHZ;
653                                         if (vco_div_selection == FPGA_VCO_DIV_8)
654                                                 sys_per = PERIOD_50_00MHZ;
655                                 }
656                                 break;
657                         case PERIOD_50_00MHZ:
658                                 if (fb_div_selection == FPGA_FB_DIV_6) {
659                                         if (vco_div_selection == FPGA_VCO_DIV_4)
660                                                 sys_per = PERIOD_75_00MHZ;
661                                         if (vco_div_selection == FPGA_VCO_DIV_6)
662                                                 sys_per = PERIOD_50_00MHZ;
663                                 }
664                                 if (fb_div_selection == FPGA_FB_DIV_10) {
665                                         if (vco_div_selection == FPGA_VCO_DIV_6)
666                                                 sys_per = PERIOD_83_33MHZ;
667                                         if (vco_div_selection == FPGA_VCO_DIV_10)
668                                                 sys_per = PERIOD_50_00MHZ;
669                                 }
670                                 if (fb_div_selection == FPGA_FB_DIV_12) {
671                                         if (vco_div_selection == FPGA_VCO_DIV_6)
672                                                 sys_per = PERIOD_100_00MHZ;
673                                         if (vco_div_selection == FPGA_VCO_DIV_8)
674                                                 sys_per = PERIOD_75_00MHZ;
675                                 }
676                                 break;
677                         case PERIOD_66_66MHZ:
678                                 if (fb_div_selection == FPGA_FB_DIV_6) {
679                                         if (vco_div_selection == FPGA_VCO_DIV_4)
680                                                 sys_per = PERIOD_100_00MHZ;
681                                         if (vco_div_selection == FPGA_VCO_DIV_6)
682                                                 sys_per = PERIOD_66_66MHZ;
683                                         if (vco_div_selection == FPGA_VCO_DIV_8)
684                                                 sys_per = PERIOD_50_00MHZ;
685                                 }
686                                 if (fb_div_selection == FPGA_FB_DIV_10) {
687                                         if (vco_div_selection == FPGA_VCO_DIV_8)
688                                                 sys_per = PERIOD_83_33MHZ;
689                                         if (vco_div_selection == FPGA_VCO_DIV_10)
690                                                 sys_per = PERIOD_66_66MHZ;
691                                 }
692                                 if (fb_div_selection == FPGA_FB_DIV_12) {
693                                         if (vco_div_selection == FPGA_VCO_DIV_8)
694                                                 sys_per = PERIOD_100_00MHZ;
695                                 }
696                                 break;
697                         default:
698                                 break;
699                 }
700
701                 if (sys_per == 0) {
702                         /* Other combinations are not supported */
703                         DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
704                         hang();
705                 }
706         } else {
707                 /* calcul system clock without cheking */
708                 /* if engineering option clock no check is selected */
709                 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
710                 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
711         }
712
713         return(sys_per);
714 }
715
716 /*-------------------------------------------------------------------------+
717 | determine_pci_clock_per.
718 +-------------------------------------------------------------------------*/
719 unsigned long determine_pci_clock_per(void)
720 {
721         unsigned long pci_clock_selection,  pci_period;
722
723         /*-------------------------------------------------------------------------+
724          | Read FPGA reg 6 to get PCI 0 FPGA reg information
725          +-------------------------------------------------------------------------*/
726         pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
727
728
729         pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
730
731         switch (pci_clock_selection) {
732                 case FPGA_REG16_PCI0_CLK_133_33:
733                         pci_period = PERIOD_133_33MHZ;
734                         break;
735                 case FPGA_REG16_PCI0_CLK_100:
736                         pci_period = PERIOD_100_00MHZ;
737                         break;
738                 case FPGA_REG16_PCI0_CLK_66_66:
739                         pci_period = PERIOD_66_66MHZ;
740                         break;
741                 default:
742                         pci_period = PERIOD_33_33MHZ;;
743                         break;
744         }
745
746         return(pci_period);
747 }
748 #endif
749
750 ulong get_OPB_freq (void)
751 {
752
753         sys_info_t sys_info;
754         get_sys_info (&sys_info);
755         return sys_info.freqOPB;
756 }
757
758 #elif defined(CONFIG_XILINX_405)
759 extern void get_sys_info (sys_info_t * sysInfo);
760 extern ulong get_PCI_freq (void);
761
762 #elif defined(CONFIG_AP1000)
763 void get_sys_info (sys_info_t * sysInfo)
764 {
765         sysInfo->freqProcessor = 240 * 1000 * 1000;
766         sysInfo->freqPLB = 80 * 1000 * 1000;
767         sysInfo->freqPCI = 33 * 1000 * 1000;
768 }
769
770 #elif defined(CONFIG_405)
771
772 void get_sys_info (sys_info_t * sysInfo)
773 {
774         sysInfo->freqVCOMhz=3125000;
775         sysInfo->freqProcessor=12*1000*1000;
776         sysInfo->freqPLB=50*1000*1000;
777         sysInfo->freqPCI=66*1000*1000;
778 }
779
780 #elif defined(CONFIG_405EP)
781 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
782 {
783         unsigned long pllmr0;
784         unsigned long pllmr1;
785         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
786         unsigned long m;
787         unsigned long pllmr0_ccdv;
788
789         /*
790          * Read PLL Mode registers
791          */
792         pllmr0 = mfdcr (cpc0_pllmr0);
793         pllmr1 = mfdcr (cpc0_pllmr1);
794
795         /*
796          * Determine forward divider A
797          */
798         sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
799
800         /*
801          * Determine forward divider B (should be equal to A)
802          */
803         sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
804
805         /*
806          * Determine FBK_DIV.
807          */
808         sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
809         if (sysInfo->pllFbkDiv == 0)
810                 sysInfo->pllFbkDiv = 16;
811
812         /*
813          * Determine PLB_DIV.
814          */
815         sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
816
817         /*
818          * Determine PCI_DIV.
819          */
820         sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
821
822         /*
823          * Determine EXTBUS_DIV.
824          */
825         sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
826
827         /*
828          * Determine OPB_DIV.
829          */
830         sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
831
832         /*
833          * Determine the M factor
834          */
835         m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
836
837         /*
838          * Determine VCO clock frequency
839          */
840         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
841                 (unsigned long long)sysClkPeriodPs;
842
843         /*
844          * Determine CPU clock frequency
845          */
846         pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
847         if (pllmr1 & PLLMR1_SSCS_MASK) {
848                 /*
849                  * This is true if FWDVA == FWDVB:
850                  * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
851                  *      / pllmr0_ccdv;
852                  */
853                 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
854                         / sysInfo->pllFwdDiv / pllmr0_ccdv;
855         } else {
856                 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
857         }
858
859         /*
860          * Determine PLB clock frequency
861          */
862         sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
863
864         sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
865
866         sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
867 }
868
869
870 /********************************************
871  * get_OPB_freq
872  * return OPB bus freq in Hz
873  *********************************************/
874 ulong get_OPB_freq (void)
875 {
876         ulong val = 0;
877
878         PPC4xx_SYS_INFO sys_info;
879
880         get_sys_info (&sys_info);
881         val = sys_info.freqPLB / sys_info.pllOpbDiv;
882
883         return val;
884 }
885
886
887 /********************************************
888  * get_PCI_freq
889  * return PCI bus freq in Hz
890  *********************************************/
891 ulong get_PCI_freq (void)
892 {
893         ulong val;
894         PPC4xx_SYS_INFO sys_info;
895
896         get_sys_info (&sys_info);
897         val = sys_info.freqPLB / sys_info.pllPciDiv;
898         return val;
899 }
900
901 #elif defined(CONFIG_405EZ)
902 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
903 {
904         unsigned long cpr_plld;
905         unsigned long cpr_pllc;
906         unsigned long cpr_primad;
907         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
908         unsigned long primad_cpudv;
909         unsigned long m;
910
911         /*
912          * Read PLL Mode registers
913          */
914         mfcpr(cprplld, cpr_plld);
915         mfcpr(cprpllc, cpr_pllc);
916
917         /*
918          * Determine forward divider A
919          */
920         sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
921
922         /*
923          * Determine forward divider B
924          */
925         sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
926         if (sysInfo->pllFwdDivB == 0)
927                 sysInfo->pllFwdDivB = 8;
928
929         /*
930          * Determine FBK_DIV.
931          */
932         sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
933         if (sysInfo->pllFbkDiv == 0)
934                 sysInfo->pllFbkDiv = 256;
935
936         /*
937          * Read CPR_PRIMAD register
938          */
939         mfcpr(cprprimad, cpr_primad);
940
941         /*
942          * Determine PLB_DIV.
943          */
944         sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
945         if (sysInfo->pllPlbDiv == 0)
946                 sysInfo->pllPlbDiv = 16;
947
948         /*
949          * Determine EXTBUS_DIV.
950          */
951         sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
952         if (sysInfo->pllExtBusDiv == 0)
953                 sysInfo->pllExtBusDiv = 16;
954
955         /*
956          * Determine OPB_DIV.
957          */
958         sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
959         if (sysInfo->pllOpbDiv == 0)
960                 sysInfo->pllOpbDiv = 16;
961
962         /*
963          * Determine the M factor
964          */
965         if (cpr_pllc & PLLC_SRC_MASK)
966                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
967         else
968                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
969
970         /*
971          * Determine VCO clock frequency
972          */
973         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
974                 (unsigned long long)sysClkPeriodPs;
975
976         /*
977          * Determine CPU clock frequency
978          */
979         primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
980         if (primad_cpudv == 0)
981                 primad_cpudv = 16;
982
983         sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
984                 sysInfo->pllFwdDiv / primad_cpudv;
985
986         /*
987          * Determine PLB clock frequency
988          */
989         sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
990                 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
991
992         sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
993                 sysInfo->pllExtBusDiv;
994
995         sysInfo->freqUART = sysInfo->freqVCOHz;
996 }
997
998 /********************************************
999  * get_OPB_freq
1000  * return OPB bus freq in Hz
1001  *********************************************/
1002 ulong get_OPB_freq (void)
1003 {
1004         ulong val = 0;
1005
1006         PPC4xx_SYS_INFO sys_info;
1007
1008         get_sys_info (&sys_info);
1009         val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1010
1011         return val;
1012 }
1013
1014 #elif defined(CONFIG_405EX)
1015
1016 /*
1017  * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1018  *   We need the specs!!!!
1019  */
1020 static unsigned char get_fbdv(unsigned char index)
1021 {
1022         unsigned char ret = 0;
1023         /* This is table should be 256 bytes.
1024          * Only take first 52 values.
1025          */
1026         unsigned char fbdv_tb[] = {
1027                 0x00, 0xff, 0x7f, 0xfd,
1028                 0x7a, 0xf5, 0x6a, 0xd5,
1029                 0x2a, 0xd4, 0x29, 0xd3,
1030                 0x26, 0xcc, 0x19, 0xb3,
1031                 0x67, 0xce, 0x1d, 0xbb,
1032                 0x77, 0xee, 0x5d, 0xba,
1033                 0x74, 0xe9, 0x52, 0xa5,
1034                 0x4b, 0x96, 0x2c, 0xd8,
1035                 0x31, 0xe3, 0x46, 0x8d,
1036                 0x1b, 0xb7, 0x6f, 0xde,
1037                 0x3d, 0xfb, 0x76, 0xed,
1038                 0x5a, 0xb5, 0x6b, 0xd6,
1039                 0x2d, 0xdb, 0x36, 0xec,
1040
1041         };
1042
1043         if ((index & 0x7f) == 0)
1044                 return 1;
1045         while (ret < sizeof (fbdv_tb)) {
1046                 if (fbdv_tb[ret] == index)
1047                         break;
1048                 ret++;
1049         }
1050         ret++;
1051
1052         return ret;
1053 }
1054
1055 #define PLL_FBK_PLL_LOCAL       0
1056 #define PLL_FBK_CPU             1
1057 #define PLL_FBK_PERCLK          5
1058
1059 void get_sys_info (sys_info_t * sysInfo)
1060 {
1061         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1062         unsigned long m = 1;
1063         unsigned int  tmp;
1064         unsigned char fwdva[16] = {
1065                 1, 2, 14, 9, 4, 11, 16, 13,
1066                 12, 5, 6, 15, 10, 7, 8, 3,
1067         };
1068         unsigned char sel, cpudv0, plb2xDiv;
1069
1070         mfcpr(cpr0_plld, tmp);
1071
1072         /*
1073          * Determine forward divider A
1074          */
1075         sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];       /* FWDVA */
1076
1077         /*
1078          * Determine FBK_DIV.
1079          */
1080         sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1081
1082         /*
1083          * Determine PLBDV0
1084          */
1085         sysInfo->pllPlbDiv = 2;
1086
1087         /*
1088          * Determine PERDV0
1089          */
1090         mfcpr(cpr0_perd, tmp);
1091         tmp = (tmp >> 24) & 0x03;
1092         sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1093
1094         /*
1095          * Determine OPBDV0
1096          */
1097         mfcpr(cpr0_opbd, tmp);
1098         tmp = (tmp >> 24) & 0x03;
1099         sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1100
1101         /* Determine PLB2XDV0 */
1102         mfcpr(cpr0_plbd, tmp);
1103         tmp = (tmp >> 16) & 0x07;
1104         plb2xDiv = (tmp == 0) ? 8 : tmp;
1105
1106         /* Determine CPUDV0 */
1107         mfcpr(cpr0_cpud, tmp);
1108         tmp = (tmp >> 24) & 0x07;
1109         cpudv0 = (tmp == 0) ? 8 : tmp;
1110
1111         /* Determine SEL(5:7) in CPR0_PLLC */
1112         mfcpr(cpr0_pllc, tmp);
1113         sel = (tmp >> 24) & 0x07;
1114
1115         /*
1116          * Determine the M factor
1117          * PLL local: M = FBDV
1118          * CPU clock: M = FBDV * FWDVA * CPUDV0
1119          * PerClk       : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1120          *
1121          */
1122         switch (sel) {
1123         case PLL_FBK_CPU:
1124                 m = sysInfo->pllFwdDiv * cpudv0;
1125                 break;
1126         case PLL_FBK_PERCLK:
1127                 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1128                         * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1129                 break;
1130         case PLL_FBK_PLL_LOCAL:
1131                 break;
1132         default:
1133                 printf("%s unknown m\n", __FUNCTION__);
1134                 return;
1135
1136         }
1137         m *= sysInfo->pllFbkDiv;
1138
1139         /*
1140          * Determine VCO clock frequency
1141          */
1142         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1143                 (unsigned long long)sysClkPeriodPs;
1144
1145         /*
1146          * Determine CPU clock frequency
1147          */
1148         sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1149
1150         /*
1151          * Determine PLB clock frequency, ddr1x should be the same
1152          */
1153         sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1154         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1155         sysInfo->freqDDR = sysInfo->freqPLB;
1156         sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1157         sysInfo->freqUART = sysInfo->freqPLB;
1158 }
1159
1160 /********************************************
1161  * get_OPB_freq
1162  * return OPB bus freq in Hz
1163  *********************************************/
1164 ulong get_OPB_freq (void)
1165 {
1166         ulong val = 0;
1167
1168         PPC4xx_SYS_INFO sys_info;
1169
1170         get_sys_info (&sys_info);
1171         val = sys_info.freqPLB / sys_info.pllOpbDiv;
1172
1173         return val;
1174 }
1175
1176 #endif
1177
1178 int get_clocks (void)
1179 {
1180 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1181     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1182     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1183     defined(CONFIG_440)
1184         sys_info_t sys_info;
1185
1186         get_sys_info (&sys_info);
1187         gd->cpu_clk = sys_info.freqProcessor;
1188         gd->bus_clk = sys_info.freqPLB;
1189
1190 #endif  /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1191
1192 #ifdef CONFIG_IOP480
1193         gd->cpu_clk = 66000000;
1194         gd->bus_clk = 66000000;
1195 #endif
1196         return (0);
1197 }
1198
1199
1200 /********************************************
1201  * get_bus_freq
1202  * return PLB bus freq in Hz
1203  *********************************************/
1204 ulong get_bus_freq (ulong dummy)
1205 {
1206         ulong val;
1207
1208 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1209     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1210     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1211     defined(CONFIG_440)
1212         sys_info_t sys_info;
1213
1214         get_sys_info (&sys_info);
1215         val = sys_info.freqPLB;
1216
1217 #elif defined(CONFIG_IOP480)
1218
1219         val = 66;
1220
1221 #else
1222 # error get_bus_freq() not implemented
1223 #endif
1224
1225         return val;
1226 }