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