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