Merge branch 'inka4x0-ng' of /home/m8/git/u-boot/
[platform/kernel/u-boot.git] / cpu / ppc4xx / speed.c
1 /*
2  * (C) Copyright 2000-2007
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 #if defined(CONFIG_405GP) || defined(CONFIG_405CR)
39
40 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
41 {
42         unsigned long pllmr;
43         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
44         uint pvr = get_pvr();
45         unsigned long psr;
46         unsigned long m;
47
48         /*
49          * Read PLL Mode register
50          */
51         pllmr = mfdcr (pllmd);
52
53         /*
54          * Read Pin Strapping register
55          */
56         psr = mfdcr (strap);
57
58         /*
59          * Determine FWD_DIV.
60          */
61         sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
62
63         /*
64          * Determine FBK_DIV.
65          */
66         sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
67         if (sysInfo->pllFbkDiv == 0) {
68                 sysInfo->pllFbkDiv = 16;
69         }
70
71         /*
72          * Determine PLB_DIV.
73          */
74         sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
75
76         /*
77          * Determine PCI_DIV.
78          */
79         sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
80
81         /*
82          * Determine EXTBUS_DIV.
83          */
84         sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
85
86         /*
87          * Determine OPB_DIV.
88          */
89         sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
90
91         /*
92          * Check if PPC405GPr used (mask minor revision field)
93          */
94         if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
95                 /*
96                  * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
97                  */
98                 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
99
100                 /*
101                  * Determine factor m depending on PLL feedback clock source
102                  */
103                 if (!(psr & PSR_PCI_ASYNC_EN)) {
104                         if (psr & PSR_NEW_MODE_EN) {
105                                 /*
106                                  * sync pci clock used as feedback (new mode)
107                                  */
108                                 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
109                         } else {
110                                 /*
111                                  * sync pci clock used as feedback (legacy mode)
112                                  */
113                                 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
114                         }
115                 } else if (psr & PSR_NEW_MODE_EN) {
116                         if (psr & PSR_PERCLK_SYNC_MODE_EN) {
117                                 /*
118                                  * PerClk used as feedback (new mode)
119                                  */
120                                 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
121                         } else {
122                                 /*
123                                  * CPU clock used as feedback (new mode)
124                                  */
125                                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
126                         }
127                 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
128                         /*
129                          * PerClk used as feedback (legacy mode)
130                          */
131                         m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
132                 } else {
133                         /*
134                          * PLB clock used as feedback (legacy mode)
135                          */
136                         m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
137                 }
138
139                 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
140                         (unsigned long long)sysClkPeriodPs;
141                 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
142                 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
143         } else {
144                 /*
145                  * Check pllFwdDiv to see if running in bypass mode where the CPU speed
146                  * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
147                  * to make sure it is within the proper range.
148                  *    spec:    VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
149                  * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
150                  */
151                 if (sysInfo->pllFwdDiv == 1) {
152                         sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
153                         sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
154                 } else {
155                         sysInfo->freqVCOHz = ( 1000000000000LL *
156                                                (unsigned long long)sysInfo->pllFwdDiv *
157                                                (unsigned long long)sysInfo->pllFbkDiv *
158                                                (unsigned long long)sysInfo->pllPlbDiv
159                                 ) / (unsigned long long)sysClkPeriodPs;
160                         sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
161                                                            sysInfo->pllFbkDiv)) * 10000;
162                         sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
163                 }
164         }
165
166         sysInfo->freqUART = sysInfo->freqProcessor;
167 }
168
169
170 /********************************************
171  * get_OPB_freq
172  * return OPB bus freq in Hz
173  *********************************************/
174 ulong get_OPB_freq (void)
175 {
176         ulong val = 0;
177
178         PPC4xx_SYS_INFO sys_info;
179
180         get_sys_info (&sys_info);
181         val = sys_info.freqPLB / sys_info.pllOpbDiv;
182
183         return val;
184 }
185
186
187 /********************************************
188  * get_PCI_freq
189  * return PCI bus freq in Hz
190  *********************************************/
191 ulong get_PCI_freq (void)
192 {
193         ulong val;
194         PPC4xx_SYS_INFO sys_info;
195
196         get_sys_info (&sys_info);
197         val = sys_info.freqPLB / sys_info.pllPciDiv;
198         return val;
199 }
200
201
202 #elif defined(CONFIG_440)
203
204 #if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
205     defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
206 void get_sys_info (sys_info_t *sysInfo)
207 {
208         unsigned long temp;
209         unsigned long reg;
210         unsigned long lfdiv;
211         unsigned long m;
212         unsigned long prbdv0;
213         /*
214           WARNING: ASSUMES the following:
215           ENG=1
216           PRADV0=1
217           PRBDV0=1
218         */
219
220         /* Decode CPR0_PLLD0 for divisors */
221         mfcpr(clk_plld, reg);
222         temp = (reg & PLLD_FWDVA_MASK) >> 16;
223         sysInfo->pllFwdDivA = temp ? temp : 16;
224         temp = (reg & PLLD_FWDVB_MASK) >> 8;
225         sysInfo->pllFwdDivB = temp ? temp: 8 ;
226         temp = (reg & PLLD_FBDV_MASK) >> 24;
227         sysInfo->pllFbkDiv = temp ? temp : 32;
228         lfdiv = reg & PLLD_LFBDV_MASK;
229
230         mfcpr(clk_opbd, reg);
231         temp = (reg & OPBDDV_MASK) >> 24;
232         sysInfo->pllOpbDiv = temp ? temp : 4;
233
234         mfcpr(clk_perd, reg);
235         temp = (reg & PERDV_MASK) >> 24;
236         sysInfo->pllExtBusDiv = temp ? temp : 8;
237
238         mfcpr(clk_primbd, reg);
239         temp = (reg & PRBDV_MASK) >> 24;
240         prbdv0 = temp ? temp : 8;
241
242         mfcpr(clk_spcid, reg);
243         temp = (reg & SPCID_MASK) >> 24;
244         sysInfo->pllPciDiv = temp ? temp : 4;
245
246         /* Calculate 'M' based on feedback source */
247         mfsdr(sdr_sdstp0, reg);
248         temp = (reg & PLLSYS0_SEL_MASK) >> 27;
249         if (temp == 0) { /* PLL output */
250                 /* Figure which pll to use */
251                 mfcpr(clk_pllc, reg);
252                 temp = (reg & PLLC_SRC_MASK) >> 29;
253                 if (!temp) /* PLLOUTA */
254                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
255                 else       /* PLLOUTB */
256                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
257         }
258         else if (temp == 1) /* CPU output */
259                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
260         else /* PerClk */
261                 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
262
263         /* Now calculate the individual clocks */
264         sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
265         sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
266         sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
267         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
268         sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
269         sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
270         sysInfo->freqUART = sysInfo->freqPLB;
271
272         /* Figure which timer source to use */
273         if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
274                 temp = sysInfo->freqProcessor / 2;  /* Max extern clock speed */
275                 if (CONFIG_SYS_CLK_FREQ > temp)
276                         sysInfo->freqTmrClk = temp;
277                 else
278                         sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
279         }
280         else  /* Internal clock */
281                 sysInfo->freqTmrClk = sysInfo->freqProcessor;
282 }
283
284 /********************************************
285  * get_PCI_freq
286  * return PCI bus freq in Hz
287  *********************************************/
288 ulong get_PCI_freq (void)
289 {
290         sys_info_t sys_info;
291         get_sys_info (&sys_info);
292         return sys_info.freqPCI;
293 }
294
295 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
296 void get_sys_info (sys_info_t * sysInfo)
297 {
298         unsigned long strp0;
299         unsigned long temp;
300         unsigned long m;
301
302         /* Extract configured divisors */
303         strp0 = mfdcr( cpc0_strp0 );
304         sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
305         sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
306         temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
307         sysInfo->pllFbkDiv = temp ? temp : 16;
308         sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
309         sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
310
311         /* Calculate 'M' based on feedback source */
312         if( strp0 & PLLSYS0_EXTSL_MASK )
313                 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
314         else
315                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
316
317         /* Now calculate the individual clocks */
318         sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
319         sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
320         sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
321         if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
322                 sysInfo->freqPLB >>= 1;
323         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
324         sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
325         sysInfo->freqUART = sysInfo->freqPLB;
326 }
327 #else
328 void get_sys_info (sys_info_t * sysInfo)
329 {
330         unsigned long strp0;
331         unsigned long strp1;
332         unsigned long temp;
333         unsigned long temp1;
334         unsigned long lfdiv;
335         unsigned long m;
336         unsigned long prbdv0;
337
338 #if defined(CONFIG_YUCCA)
339         unsigned long sys_freq;
340         unsigned long sys_per=0;
341         unsigned long msr;
342         unsigned long pci_clock_per;
343         unsigned long sdr_ddrpll;
344
345         /*-------------------------------------------------------------------------+
346          | Get the system clock period.
347          +-------------------------------------------------------------------------*/
348         sys_per = determine_sysper();
349
350         msr = (mfmsr () & ~(MSR_EE));   /* disable interrupts */
351
352         /*-------------------------------------------------------------------------+
353          | Calculate the system clock speed from the period.
354          +-------------------------------------------------------------------------*/
355         sys_freq = (ONE_BILLION / sys_per) * 1000;
356 #endif
357
358         /* Extract configured divisors */
359         mfsdr( sdr_sdstp0,strp0 );
360         mfsdr( sdr_sdstp1,strp1 );
361
362         temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
363         sysInfo->pllFwdDivA = temp ? temp : 16 ;
364         temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
365         sysInfo->pllFwdDivB = temp ? temp: 8 ;
366         temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
367         sysInfo->pllFbkDiv = temp ? temp : 32;
368         temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
369         sysInfo->pllOpbDiv = temp ? temp : 4;
370         temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
371         sysInfo->pllExtBusDiv = temp ? temp : 4;
372         prbdv0 = (strp0 >> 2) & 0x7;
373
374         /* Calculate 'M' based on feedback source */
375         temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
376         temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
377         lfdiv = temp1 ? temp1 : 64;
378         if (temp == 0) { /* PLL output */
379                 /* Figure which pll to use */
380                 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
381                 if (!temp)
382                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
383                 else
384                         m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
385         }
386         else if (temp == 1) /* CPU output */
387                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
388         else /* PerClk */
389                 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
390
391         /* Now calculate the individual clocks */
392 #if defined(CONFIG_YUCCA)
393         sysInfo->freqVCOMhz = (m * sys_freq) ;
394 #else
395         sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
396 #endif
397         sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
398         sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
399         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
400         sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
401
402 #if defined(CONFIG_YUCCA)
403         /* Determine PCI Clock Period */
404         pci_clock_per = determine_pci_clock_per();
405         sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
406         mfsdr(sdr_ddr0, sdr_ddrpll);
407         sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
408 #endif
409
410         sysInfo->freqUART = sysInfo->freqPLB;
411 }
412
413 #endif
414
415 #if defined(CONFIG_YUCCA)
416 unsigned long determine_sysper(void)
417 {
418         unsigned int fpga_clocking_reg;
419         unsigned int master_clock_selection;
420         unsigned long master_clock_per = 0;
421         unsigned long fb_div_selection;
422         unsigned int vco_div_reg_value;
423         unsigned long vco_div_selection;
424         unsigned long sys_per = 0;
425         int extClkVal;
426
427         /*-------------------------------------------------------------------------+
428          | Read FPGA reg 0 and reg 1 to get FPGA reg information
429          +-------------------------------------------------------------------------*/
430         fpga_clocking_reg = in16(FPGA_REG16);
431
432
433         /* Determine Master Clock Source Selection */
434         master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
435
436         switch(master_clock_selection) {
437                 case FPGA_REG16_MASTER_CLK_66_66:
438                         master_clock_per = PERIOD_66_66MHZ;
439                         break;
440                 case FPGA_REG16_MASTER_CLK_50:
441                         master_clock_per = PERIOD_50_00MHZ;
442                         break;
443                 case FPGA_REG16_MASTER_CLK_33_33:
444                         master_clock_per = PERIOD_33_33MHZ;
445                         break;
446                 case FPGA_REG16_MASTER_CLK_25:
447                         master_clock_per = PERIOD_25_00MHZ;
448                         break;
449                 case FPGA_REG16_MASTER_CLK_EXT:
450                         if ((extClkVal==EXTCLK_33_33)
451                                         && (extClkVal==EXTCLK_50)
452                                         && (extClkVal==EXTCLK_66_66)
453                                         && (extClkVal==EXTCLK_83)) {
454                                 /* calculate master clock period from external clock value */
455                                 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
456                         } else {
457                                 /* Unsupported */
458                                 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
459                                 hang();
460                         }
461                         break;
462                 default:
463                         /* Unsupported */
464                         DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
465                         hang();
466                         break;
467         }
468
469         /* Determine FB divisors values */
470         if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
471                 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
472                         fb_div_selection = FPGA_FB_DIV_6;
473                 else
474                         fb_div_selection = FPGA_FB_DIV_12;
475         } else {
476                 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
477                         fb_div_selection = FPGA_FB_DIV_10;
478                 else
479                         fb_div_selection = FPGA_FB_DIV_20;
480         }
481
482         /* Determine VCO divisors values */
483         vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
484
485         switch(vco_div_reg_value) {
486                 case FPGA_REG16_VCO_DIV_4:
487                         vco_div_selection = FPGA_VCO_DIV_4;
488                         break;
489                 case FPGA_REG16_VCO_DIV_6:
490                         vco_div_selection = FPGA_VCO_DIV_6;
491                         break;
492                 case FPGA_REG16_VCO_DIV_8:
493                         vco_div_selection = FPGA_VCO_DIV_8;
494                         break;
495                 case FPGA_REG16_VCO_DIV_10:
496                 default:
497                         vco_div_selection = FPGA_VCO_DIV_10;
498                         break;
499         }
500
501         if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
502                 switch(master_clock_per) {
503                         case PERIOD_25_00MHZ:
504                                 if (fb_div_selection == FPGA_FB_DIV_12) {
505                                         if (vco_div_selection == FPGA_VCO_DIV_4)
506                                                 sys_per = PERIOD_75_00MHZ;
507                                         if (vco_div_selection == FPGA_VCO_DIV_6)
508                                                 sys_per = PERIOD_50_00MHZ;
509                                 }
510                                 break;
511                         case PERIOD_33_33MHZ:
512                                 if (fb_div_selection == FPGA_FB_DIV_6) {
513                                         if (vco_div_selection == FPGA_VCO_DIV_4)
514                                                 sys_per = PERIOD_50_00MHZ;
515                                         if (vco_div_selection == FPGA_VCO_DIV_6)
516                                                 sys_per = PERIOD_33_33MHZ;
517                                 }
518                                 if (fb_div_selection == FPGA_FB_DIV_10) {
519                                         if (vco_div_selection == FPGA_VCO_DIV_4)
520                                                 sys_per = PERIOD_83_33MHZ;
521                                         if (vco_div_selection == FPGA_VCO_DIV_10)
522                                                 sys_per = PERIOD_33_33MHZ;
523                                 }
524                                 if (fb_div_selection == FPGA_FB_DIV_12) {
525                                         if (vco_div_selection == FPGA_VCO_DIV_4)
526                                                 sys_per = PERIOD_100_00MHZ;
527                                         if (vco_div_selection == FPGA_VCO_DIV_6)
528                                                 sys_per = PERIOD_66_66MHZ;
529                                         if (vco_div_selection == FPGA_VCO_DIV_8)
530                                                 sys_per = PERIOD_50_00MHZ;
531                                 }
532                                 break;
533                         case PERIOD_50_00MHZ:
534                                 if (fb_div_selection == FPGA_FB_DIV_6) {
535                                         if (vco_div_selection == FPGA_VCO_DIV_4)
536                                                 sys_per = PERIOD_75_00MHZ;
537                                         if (vco_div_selection == FPGA_VCO_DIV_6)
538                                                 sys_per = PERIOD_50_00MHZ;
539                                 }
540                                 if (fb_div_selection == FPGA_FB_DIV_10) {
541                                         if (vco_div_selection == FPGA_VCO_DIV_6)
542                                                 sys_per = PERIOD_83_33MHZ;
543                                         if (vco_div_selection == FPGA_VCO_DIV_10)
544                                                 sys_per = PERIOD_50_00MHZ;
545                                 }
546                                 if (fb_div_selection == FPGA_FB_DIV_12) {
547                                         if (vco_div_selection == FPGA_VCO_DIV_6)
548                                                 sys_per = PERIOD_100_00MHZ;
549                                         if (vco_div_selection == FPGA_VCO_DIV_8)
550                                                 sys_per = PERIOD_75_00MHZ;
551                                 }
552                                 break;
553                         case PERIOD_66_66MHZ:
554                                 if (fb_div_selection == FPGA_FB_DIV_6) {
555                                         if (vco_div_selection == FPGA_VCO_DIV_4)
556                                                 sys_per = PERIOD_100_00MHZ;
557                                         if (vco_div_selection == FPGA_VCO_DIV_6)
558                                                 sys_per = PERIOD_66_66MHZ;
559                                         if (vco_div_selection == FPGA_VCO_DIV_8)
560                                                 sys_per = PERIOD_50_00MHZ;
561                                 }
562                                 if (fb_div_selection == FPGA_FB_DIV_10) {
563                                         if (vco_div_selection == FPGA_VCO_DIV_8)
564                                                 sys_per = PERIOD_83_33MHZ;
565                                         if (vco_div_selection == FPGA_VCO_DIV_10)
566                                                 sys_per = PERIOD_66_66MHZ;
567                                 }
568                                 if (fb_div_selection == FPGA_FB_DIV_12) {
569                                         if (vco_div_selection == FPGA_VCO_DIV_8)
570                                                 sys_per = PERIOD_100_00MHZ;
571                                 }
572                                 break;
573                         default:
574                                 break;
575                 }
576
577                 if (sys_per == 0) {
578                         /* Other combinations are not supported */
579                         DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
580                         hang();
581                 }
582         } else {
583                 /* calcul system clock without cheking */
584                 /* if engineering option clock no check is selected */
585                 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
586                 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
587         }
588
589         return(sys_per);
590 }
591
592 /*-------------------------------------------------------------------------+
593 | determine_pci_clock_per.
594 +-------------------------------------------------------------------------*/
595 unsigned long determine_pci_clock_per(void)
596 {
597         unsigned long pci_clock_selection,  pci_period;
598
599         /*-------------------------------------------------------------------------+
600          | Read FPGA reg 6 to get PCI 0 FPGA reg information
601          +-------------------------------------------------------------------------*/
602         pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
603
604
605         pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
606
607         switch (pci_clock_selection) {
608                 case FPGA_REG16_PCI0_CLK_133_33:
609                         pci_period = PERIOD_133_33MHZ;
610                         break;
611                 case FPGA_REG16_PCI0_CLK_100:
612                         pci_period = PERIOD_100_00MHZ;
613                         break;
614                 case FPGA_REG16_PCI0_CLK_66_66:
615                         pci_period = PERIOD_66_66MHZ;
616                         break;
617                 default:
618                         pci_period = PERIOD_33_33MHZ;;
619                         break;
620         }
621
622         return(pci_period);
623 }
624 #endif
625
626 ulong get_OPB_freq (void)
627 {
628
629         sys_info_t sys_info;
630         get_sys_info (&sys_info);
631         return sys_info.freqOPB;
632 }
633
634 #elif defined(CONFIG_XILINX_ML300)
635 extern void get_sys_info (sys_info_t * sysInfo);
636 extern ulong get_PCI_freq (void);
637
638 #elif defined(CONFIG_AP1000)
639 void get_sys_info (sys_info_t * sysInfo)
640 {
641         sysInfo->freqProcessor = 240 * 1000 * 1000;
642         sysInfo->freqPLB = 80 * 1000 * 1000;
643         sysInfo->freqPCI = 33 * 1000 * 1000;
644 }
645
646 #elif defined(CONFIG_405)
647
648 void get_sys_info (sys_info_t * sysInfo)
649 {
650         sysInfo->freqVCOMhz=3125000;
651         sysInfo->freqProcessor=12*1000*1000;
652         sysInfo->freqPLB=50*1000*1000;
653         sysInfo->freqPCI=66*1000*1000;
654 }
655
656 #elif defined(CONFIG_405EP)
657 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
658 {
659         unsigned long pllmr0;
660         unsigned long pllmr1;
661         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
662         unsigned long m;
663         unsigned long pllmr0_ccdv;
664
665         /*
666          * Read PLL Mode registers
667          */
668         pllmr0 = mfdcr (cpc0_pllmr0);
669         pllmr1 = mfdcr (cpc0_pllmr1);
670
671         /*
672          * Determine forward divider A
673          */
674         sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
675
676         /*
677          * Determine forward divider B (should be equal to A)
678          */
679         sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
680
681         /*
682          * Determine FBK_DIV.
683          */
684         sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
685         if (sysInfo->pllFbkDiv == 0)
686                 sysInfo->pllFbkDiv = 16;
687
688         /*
689          * Determine PLB_DIV.
690          */
691         sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
692
693         /*
694          * Determine PCI_DIV.
695          */
696         sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
697
698         /*
699          * Determine EXTBUS_DIV.
700          */
701         sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
702
703         /*
704          * Determine OPB_DIV.
705          */
706         sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
707
708         /*
709          * Determine the M factor
710          */
711         m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
712
713         /*
714          * Determine VCO clock frequency
715          */
716         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
717                 (unsigned long long)sysClkPeriodPs;
718
719         /*
720          * Determine CPU clock frequency
721          */
722         pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
723         if (pllmr1 & PLLMR1_SSCS_MASK) {
724                 /*
725                  * This is true if FWDVA == FWDVB:
726                  * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
727                  *      / pllmr0_ccdv;
728                  */
729                 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
730                         / sysInfo->pllFwdDiv / pllmr0_ccdv;
731         } else {
732                 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
733         }
734
735         /*
736          * Determine PLB clock frequency
737          */
738         sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
739
740         sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
741
742         sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
743 }
744
745
746 /********************************************
747  * get_OPB_freq
748  * return OPB bus freq in Hz
749  *********************************************/
750 ulong get_OPB_freq (void)
751 {
752         ulong val = 0;
753
754         PPC4xx_SYS_INFO sys_info;
755
756         get_sys_info (&sys_info);
757         val = sys_info.freqPLB / sys_info.pllOpbDiv;
758
759         return val;
760 }
761
762
763 /********************************************
764  * get_PCI_freq
765  * return PCI bus freq in Hz
766  *********************************************/
767 ulong get_PCI_freq (void)
768 {
769         ulong val;
770         PPC4xx_SYS_INFO sys_info;
771
772         get_sys_info (&sys_info);
773         val = sys_info.freqPLB / sys_info.pllPciDiv;
774         return val;
775 }
776
777 #elif defined(CONFIG_405EZ)
778 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
779 {
780         unsigned long cpr_plld;
781         unsigned long cpr_pllc;
782         unsigned long cpr_primad;
783         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
784         unsigned long primad_cpudv;
785         unsigned long m;
786
787         /*
788          * Read PLL Mode registers
789          */
790         mfcpr(cprplld, cpr_plld);
791         mfcpr(cprpllc, cpr_pllc);
792
793         /*
794          * Determine forward divider A
795          */
796         sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
797
798         /*
799          * Determine forward divider B
800          */
801         sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
802         if (sysInfo->pllFwdDivB == 0)
803                 sysInfo->pllFwdDivB = 8;
804
805         /*
806          * Determine FBK_DIV.
807          */
808         sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
809         if (sysInfo->pllFbkDiv == 0)
810                 sysInfo->pllFbkDiv = 256;
811
812         /*
813          * Read CPR_PRIMAD register
814          */
815         mfcpr(cprprimad, cpr_primad);
816
817         /*
818          * Determine PLB_DIV.
819          */
820         sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
821         if (sysInfo->pllPlbDiv == 0)
822                 sysInfo->pllPlbDiv = 16;
823
824         /*
825          * Determine EXTBUS_DIV.
826          */
827         sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
828         if (sysInfo->pllExtBusDiv == 0)
829                 sysInfo->pllExtBusDiv = 16;
830
831         /*
832          * Determine OPB_DIV.
833          */
834         sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
835         if (sysInfo->pllOpbDiv == 0)
836                 sysInfo->pllOpbDiv = 16;
837
838         /*
839          * Determine the M factor
840          */
841         if (cpr_pllc & PLLC_SRC_MASK)
842                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
843         else
844                 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
845
846         /*
847          * Determine VCO clock frequency
848          */
849         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
850                 (unsigned long long)sysClkPeriodPs;
851
852         /*
853          * Determine CPU clock frequency
854          */
855         primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
856         if (primad_cpudv == 0)
857                 primad_cpudv = 16;
858
859         sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
860                 sysInfo->pllFwdDiv / primad_cpudv;
861
862         /*
863          * Determine PLB clock frequency
864          */
865         sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
866                 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
867
868         sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
869                 sysInfo->pllExtBusDiv;
870
871         sysInfo->freqUART = sysInfo->freqVCOHz;
872 }
873
874 /********************************************
875  * get_OPB_freq
876  * return OPB bus freq in Hz
877  *********************************************/
878 ulong get_OPB_freq (void)
879 {
880         ulong val = 0;
881
882         PPC4xx_SYS_INFO sys_info;
883
884         get_sys_info (&sys_info);
885         val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
886
887         return val;
888 }
889
890 #elif defined(CONFIG_405EX)
891
892 /*
893  * TODO: We need to get the CPR registers and calculate these values correctly!!!!
894  *   We need the specs!!!!
895  */
896 static unsigned char get_fbdv(unsigned char index)
897 {
898         unsigned char ret = 0;
899         /* This is table should be 256 bytes.
900          * Only take first 52 values.
901          */
902         unsigned char fbdv_tb[] = {
903                 0x00, 0xff, 0x7f, 0xfd,
904                 0x7a, 0xf5, 0x6a, 0xd5,
905                 0x2a, 0xd4, 0x29, 0xd3,
906                 0x26, 0xcc, 0x19, 0xb3,
907                 0x67, 0xce, 0x1d, 0xbb,
908                 0x77, 0xee, 0x5d, 0xba,
909                 0x74, 0xe9, 0x52, 0xa5,
910                 0x4b, 0x96, 0x2c, 0xd8,
911                 0x31, 0xe3, 0x46, 0x8d,
912                 0x1b, 0xb7, 0x6f, 0xde,
913                 0x3d, 0xfb, 0x76, 0xed,
914                 0x5a, 0xb5, 0x6b, 0xd6,
915                 0x2d, 0xdb, 0x36, 0xec,
916
917         };
918
919         if ((index & 0x7f) == 0)
920                 return 1;
921         while (ret < sizeof (fbdv_tb)) {
922                 if (fbdv_tb[ret] == index)
923                         break;
924                 ret++;
925         }
926         ret++;
927
928         return ret;
929 }
930
931 #define PLL_FBK_PLL_LOCAL       0
932 #define PLL_FBK_CPU             1
933 #define PLL_FBK_PERCLK          5
934
935 void get_sys_info (sys_info_t * sysInfo)
936 {
937         unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
938         unsigned long m = 1;
939         unsigned int  tmp;
940         unsigned char fwdva[16] = {
941                 1, 2, 14, 9, 4, 11, 16, 13,
942                 12, 5, 6, 15, 10, 7, 8, 3,
943         };
944         unsigned char sel, cpudv0, plb2xDiv;
945
946         mfcpr(cpr0_plld, tmp);
947
948         /*
949          * Determine forward divider A
950          */
951         sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];       /* FWDVA */
952
953         /*
954          * Determine FBK_DIV.
955          */
956         sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
957
958         /*
959          * Determine PLBDV0
960          */
961         sysInfo->pllPlbDiv = 2;
962
963         /*
964          * Determine PERDV0
965          */
966         mfcpr(cpr0_perd, tmp);
967         tmp = (tmp >> 24) & 0x03;
968         sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
969
970         /*
971          * Determine OPBDV0
972          */
973         mfcpr(cpr0_opbd, tmp);
974         tmp = (tmp >> 24) & 0x03;
975         sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
976
977         /* Determine PLB2XDV0 */
978         mfcpr(cpr0_plbd, tmp);
979         tmp = (tmp >> 16) & 0x07;
980         plb2xDiv = (tmp == 0) ? 8 : tmp;
981
982         /* Determine CPUDV0 */
983         mfcpr(cpr0_cpud, tmp);
984         tmp = (tmp >> 24) & 0x07;
985         cpudv0 = (tmp == 0) ? 8 : tmp;
986
987         /* Determine SEL(5:7) in CPR0_PLLC */
988         mfcpr(cpr0_pllc, tmp);
989         sel = (tmp >> 24) & 0x07;
990
991         /*
992          * Determine the M factor
993          * PLL local: M = FBDV
994          * CPU clock: M = FBDV * FWDVA * CPUDV0
995          * PerClk       : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
996          *
997          */
998         switch (sel) {
999         case PLL_FBK_CPU:
1000                 m = sysInfo->pllFwdDiv * cpudv0;
1001                 break;
1002         case PLL_FBK_PERCLK:
1003                 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1004                         * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1005                 break;
1006         case PLL_FBK_PLL_LOCAL:
1007                 break;
1008         default:
1009                 printf("%s unknown m\n", __FUNCTION__);
1010                 return;
1011
1012         }
1013         m *= sysInfo->pllFbkDiv;
1014
1015         /*
1016          * Determine VCO clock frequency
1017          */
1018         sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1019                 (unsigned long long)sysClkPeriodPs;
1020
1021         /*
1022          * Determine CPU clock frequency
1023          */
1024         sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1025
1026         /*
1027          * Determine PLB clock frequency, ddr1x should be the same
1028          */
1029         sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1030         sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1031         sysInfo->freqDDR = sysInfo->freqPLB;
1032         sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1033         sysInfo->freqUART = sysInfo->freqPLB;
1034 }
1035
1036 /********************************************
1037  * get_OPB_freq
1038  * return OPB bus freq in Hz
1039  *********************************************/
1040 ulong get_OPB_freq (void)
1041 {
1042         ulong val = 0;
1043
1044         PPC4xx_SYS_INFO sys_info;
1045
1046         get_sys_info (&sys_info);
1047         val = sys_info.freqPLB / sys_info.pllOpbDiv;
1048
1049         return val;
1050 }
1051
1052 #endif
1053
1054 int get_clocks (void)
1055 {
1056 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1057     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1058     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1059     defined(CONFIG_440)
1060         sys_info_t sys_info;
1061
1062         get_sys_info (&sys_info);
1063         gd->cpu_clk = sys_info.freqProcessor;
1064         gd->bus_clk = sys_info.freqPLB;
1065
1066 #endif  /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1067
1068 #ifdef CONFIG_IOP480
1069         gd->cpu_clk = 66000000;
1070         gd->bus_clk = 66000000;
1071 #endif
1072         return (0);
1073 }
1074
1075
1076 /********************************************
1077  * get_bus_freq
1078  * return PLB bus freq in Hz
1079  *********************************************/
1080 ulong get_bus_freq (ulong dummy)
1081 {
1082         ulong val;
1083
1084 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1085     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1086     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1087     defined(CONFIG_440)
1088         sys_info_t sys_info;
1089
1090         get_sys_info (&sys_info);
1091         val = sys_info.freqPLB;
1092
1093 #elif defined(CONFIG_IOP480)
1094
1095         val = 66;
1096
1097 #else
1098 # error get_bus_freq() not implemented
1099 #endif
1100
1101         return val;
1102 }