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