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