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