2 * (C) Copyright 2000-2008
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
25 #include <ppc_asm.tmpl>
27 #include <asm/processor.h>
29 DECLARE_GLOBAL_DATA_PTR;
31 #define ONE_BILLION 1000000000
33 #define DEBUGF(fmt,args...) printf(fmt ,##args)
35 #define DEBUGF(fmt,args...)
38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
40 #if defined(CONFIG_405GP) || defined(CONFIG_405CR)
42 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
45 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
51 * Read PLL Mode register
53 pllmr = mfdcr (pllmd);
56 * Read Pin Strapping register
63 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
68 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
69 if (sysInfo->pllFbkDiv == 0) {
70 sysInfo->pllFbkDiv = 16;
76 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
81 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
84 * Determine EXTBUS_DIV.
86 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
91 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
94 * Check if PPC405GPr used (mask minor revision field)
96 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
98 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
100 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
103 * Determine factor m depending on PLL feedback clock source
105 if (!(psr & PSR_PCI_ASYNC_EN)) {
106 if (psr & PSR_NEW_MODE_EN) {
108 * sync pci clock used as feedback (new mode)
110 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
113 * sync pci clock used as feedback (legacy mode)
115 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
117 } else if (psr & PSR_NEW_MODE_EN) {
118 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
120 * PerClk used as feedback (new mode)
122 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
125 * CPU clock used as feedback (new mode)
127 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
129 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
131 * PerClk used as feedback (legacy mode)
133 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
136 * PLB clock used as feedback (legacy mode)
138 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
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);
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.
153 if (sysInfo->pllFwdDiv == 1) {
154 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
155 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
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;
168 sysInfo->freqUART = sysInfo->freqProcessor;
172 /********************************************
174 * return OPB bus freq in Hz
175 *********************************************/
176 ulong get_OPB_freq (void)
180 PPC4xx_SYS_INFO sys_info;
182 get_sys_info (&sys_info);
183 val = sys_info.freqPLB / sys_info.pllOpbDiv;
189 /********************************************
191 * return PCI bus freq in Hz
192 *********************************************/
193 ulong get_PCI_freq (void)
196 PPC4xx_SYS_INFO sys_info;
198 get_sys_info (&sys_info);
199 val = sys_info.freqPLB / sys_info.pllPciDiv;
204 #elif defined(CONFIG_440)
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
213 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
217 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
218 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
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 */
256 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
260 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
261 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
268 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
271 void get_sys_info (sys_info_t * sysInfo)
277 unsigned long plbedv0;
279 /* Extract configured divisors */
280 mfsdr(sdr_sdstp0, strp0);
281 mfsdr(sdr_sdstp1, strp1);
283 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
284 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
286 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
287 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
289 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
290 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
292 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
293 sysInfo->pllOpbDiv = temp ? temp : 4;
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;
299 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
300 plbedv0 = temp ? temp: 8;
302 /* Calculate 'M' based on feedback source */
303 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
305 /* PLL internal feedback */
306 m = sysInfo->pllFbkDiv;
308 /* PLL PerClk feedback */
309 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
310 sysInfo->pllExtBusDiv;
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;
325 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
326 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
327 void get_sys_info (sys_info_t *sysInfo)
333 unsigned long prbdv0;
335 WARNING: ASSUMES the following:
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;
351 mfcpr(clk_opbd, reg);
352 temp = (reg & OPBDDV_MASK) >> 24;
353 sysInfo->pllOpbDiv = temp ? temp : 4;
355 mfcpr(clk_perd, reg);
356 temp = (reg & PERDV_MASK) >> 24;
357 sysInfo->pllExtBusDiv = temp ? temp : 8;
359 mfcpr(clk_primbd, reg);
360 temp = (reg & PRBDV_MASK) >> 24;
361 prbdv0 = temp ? temp : 8;
363 mfcpr(clk_spcid, reg);
364 temp = (reg & SPCID_MASK) >> 24;
365 sysInfo->pllPciDiv = temp ? temp : 4;
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;
377 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
379 else if (temp == 1) /* CPU output */
380 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
382 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
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;
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;
399 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
401 else /* Internal clock */
402 sysInfo->freqTmrClk = sysInfo->freqProcessor;
405 /********************************************
407 * return PCI bus freq in Hz
408 *********************************************/
409 ulong get_PCI_freq (void)
412 get_sys_info (&sys_info);
413 return sys_info.freqPCI;
416 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
417 void get_sys_info (sys_info_t * sysInfo)
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);
432 /* Calculate 'M' based on feedback source */
433 if( strp0 & PLLSYS0_EXTSL_MASK )
434 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
436 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
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;
449 void get_sys_info (sys_info_t * sysInfo)
457 unsigned long prbdv0;
459 #if defined(CONFIG_YUCCA)
460 unsigned long sys_freq;
461 unsigned long sys_per=0;
463 unsigned long pci_clock_per;
464 unsigned long sdr_ddrpll;
466 /*-------------------------------------------------------------------------+
467 | Get the system clock period.
468 +-------------------------------------------------------------------------*/
469 sys_per = determine_sysper();
471 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
473 /*-------------------------------------------------------------------------+
474 | Calculate the system clock speed from the period.
475 +-------------------------------------------------------------------------*/
476 sys_freq = (ONE_BILLION / sys_per) * 1000;
479 /* Extract configured divisors */
480 mfsdr( sdr_sdstp0,strp0 );
481 mfsdr( sdr_sdstp1,strp1 );
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;
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;
503 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
505 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
507 else if (temp == 1) /* CPU output */
508 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
510 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
512 /* Now calculate the individual clocks */
513 #if defined(CONFIG_YUCCA)
514 sysInfo->freqVCOMhz = (m * sys_freq) ;
516 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
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;
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));
531 sysInfo->freqUART = sysInfo->freqPLB;
536 #if defined(CONFIG_YUCCA)
537 unsigned long determine_sysper(void)
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;
548 /*-------------------------------------------------------------------------+
549 | Read FPGA reg 0 and reg 1 to get FPGA reg information
550 +-------------------------------------------------------------------------*/
551 fpga_clocking_reg = in16(FPGA_REG16);
554 /* Determine Master Clock Source Selection */
555 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
557 switch(master_clock_selection) {
558 case FPGA_REG16_MASTER_CLK_66_66:
559 master_clock_per = PERIOD_66_66MHZ;
561 case FPGA_REG16_MASTER_CLK_50:
562 master_clock_per = PERIOD_50_00MHZ;
564 case FPGA_REG16_MASTER_CLK_33_33:
565 master_clock_per = PERIOD_33_33MHZ;
567 case FPGA_REG16_MASTER_CLK_25:
568 master_clock_per = PERIOD_25_00MHZ;
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;
579 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
585 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
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;
595 fb_div_selection = FPGA_FB_DIV_12;
597 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
598 fb_div_selection = FPGA_FB_DIV_10;
600 fb_div_selection = FPGA_FB_DIV_20;
603 /* Determine VCO divisors values */
604 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
606 switch(vco_div_reg_value) {
607 case FPGA_REG16_VCO_DIV_4:
608 vco_div_selection = FPGA_VCO_DIV_4;
610 case FPGA_REG16_VCO_DIV_6:
611 vco_div_selection = FPGA_VCO_DIV_6;
613 case FPGA_REG16_VCO_DIV_8:
614 vco_div_selection = FPGA_VCO_DIV_8;
616 case FPGA_REG16_VCO_DIV_10:
618 vco_div_selection = FPGA_VCO_DIV_10;
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;
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;
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;
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;
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;
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;
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;
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;
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;
689 if (fb_div_selection == FPGA_FB_DIV_12) {
690 if (vco_div_selection == FPGA_VCO_DIV_8)
691 sys_per = PERIOD_100_00MHZ;
699 /* Other combinations are not supported */
700 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
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;
713 /*-------------------------------------------------------------------------+
714 | determine_pci_clock_per.
715 +-------------------------------------------------------------------------*/
716 unsigned long determine_pci_clock_per(void)
718 unsigned long pci_clock_selection, pci_period;
720 /*-------------------------------------------------------------------------+
721 | Read FPGA reg 6 to get PCI 0 FPGA reg information
722 +-------------------------------------------------------------------------*/
723 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
726 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
728 switch (pci_clock_selection) {
729 case FPGA_REG16_PCI0_CLK_133_33:
730 pci_period = PERIOD_133_33MHZ;
732 case FPGA_REG16_PCI0_CLK_100:
733 pci_period = PERIOD_100_00MHZ;
735 case FPGA_REG16_PCI0_CLK_66_66:
736 pci_period = PERIOD_66_66MHZ;
739 pci_period = PERIOD_33_33MHZ;;
747 ulong get_OPB_freq (void)
751 get_sys_info (&sys_info);
752 return sys_info.freqOPB;
755 #elif defined(CONFIG_XILINX_ML300)
756 extern void get_sys_info (sys_info_t * sysInfo);
757 extern ulong get_PCI_freq (void);
759 #elif defined(CONFIG_AP1000)
760 void get_sys_info (sys_info_t * sysInfo)
762 sysInfo->freqProcessor = 240 * 1000 * 1000;
763 sysInfo->freqPLB = 80 * 1000 * 1000;
764 sysInfo->freqPCI = 33 * 1000 * 1000;
767 #elif defined(CONFIG_405)
769 void get_sys_info (sys_info_t * sysInfo)
771 sysInfo->freqVCOMhz=3125000;
772 sysInfo->freqProcessor=12*1000*1000;
773 sysInfo->freqPLB=50*1000*1000;
774 sysInfo->freqPCI=66*1000*1000;
777 #elif defined(CONFIG_405EP)
778 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
780 unsigned long pllmr0;
781 unsigned long pllmr1;
782 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
784 unsigned long pllmr0_ccdv;
787 * Read PLL Mode registers
789 pllmr0 = mfdcr (cpc0_pllmr0);
790 pllmr1 = mfdcr (cpc0_pllmr1);
793 * Determine forward divider A
795 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
798 * Determine forward divider B (should be equal to A)
800 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
805 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
806 if (sysInfo->pllFbkDiv == 0)
807 sysInfo->pllFbkDiv = 16;
812 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
817 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
820 * Determine EXTBUS_DIV.
822 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
827 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
830 * Determine the M factor
832 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
835 * Determine VCO clock frequency
837 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
838 (unsigned long long)sysClkPeriodPs;
841 * Determine CPU clock frequency
843 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
844 if (pllmr1 & PLLMR1_SSCS_MASK) {
846 * This is true if FWDVA == FWDVB:
847 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
850 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
851 / sysInfo->pllFwdDiv / pllmr0_ccdv;
853 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
857 * Determine PLB clock frequency
859 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
861 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
863 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
867 /********************************************
869 * return OPB bus freq in Hz
870 *********************************************/
871 ulong get_OPB_freq (void)
875 PPC4xx_SYS_INFO sys_info;
877 get_sys_info (&sys_info);
878 val = sys_info.freqPLB / sys_info.pllOpbDiv;
884 /********************************************
886 * return PCI bus freq in Hz
887 *********************************************/
888 ulong get_PCI_freq (void)
891 PPC4xx_SYS_INFO sys_info;
893 get_sys_info (&sys_info);
894 val = sys_info.freqPLB / sys_info.pllPciDiv;
898 #elif defined(CONFIG_405EZ)
899 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
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;
909 * Read PLL Mode registers
911 mfcpr(cprplld, cpr_plld);
912 mfcpr(cprpllc, cpr_pllc);
915 * Determine forward divider A
917 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
920 * Determine forward divider B
922 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
923 if (sysInfo->pllFwdDivB == 0)
924 sysInfo->pllFwdDivB = 8;
929 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
930 if (sysInfo->pllFbkDiv == 0)
931 sysInfo->pllFbkDiv = 256;
934 * Read CPR_PRIMAD register
936 mfcpr(cprprimad, cpr_primad);
941 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
942 if (sysInfo->pllPlbDiv == 0)
943 sysInfo->pllPlbDiv = 16;
946 * Determine EXTBUS_DIV.
948 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
949 if (sysInfo->pllExtBusDiv == 0)
950 sysInfo->pllExtBusDiv = 16;
955 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
956 if (sysInfo->pllOpbDiv == 0)
957 sysInfo->pllOpbDiv = 16;
960 * Determine the M factor
962 if (cpr_pllc & PLLC_SRC_MASK)
963 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
965 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
968 * Determine VCO clock frequency
970 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
971 (unsigned long long)sysClkPeriodPs;
974 * Determine CPU clock frequency
976 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
977 if (primad_cpudv == 0)
980 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
981 sysInfo->pllFwdDiv / primad_cpudv;
984 * Determine PLB clock frequency
986 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
987 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
989 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
990 sysInfo->pllExtBusDiv;
992 sysInfo->freqUART = sysInfo->freqVCOHz;
995 /********************************************
997 * return OPB bus freq in Hz
998 *********************************************/
999 ulong get_OPB_freq (void)
1003 PPC4xx_SYS_INFO sys_info;
1005 get_sys_info (&sys_info);
1006 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1011 #elif defined(CONFIG_405EX)
1014 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1015 * We need the specs!!!!
1017 static unsigned char get_fbdv(unsigned char index)
1019 unsigned char ret = 0;
1020 /* This is table should be 256 bytes.
1021 * Only take first 52 values.
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,
1040 if ((index & 0x7f) == 0)
1042 while (ret < sizeof (fbdv_tb)) {
1043 if (fbdv_tb[ret] == index)
1052 #define PLL_FBK_PLL_LOCAL 0
1053 #define PLL_FBK_CPU 1
1054 #define PLL_FBK_PERCLK 5
1056 void get_sys_info (sys_info_t * sysInfo)
1058 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1059 unsigned long m = 1;
1061 unsigned char fwdva[16] = {
1062 1, 2, 14, 9, 4, 11, 16, 13,
1063 12, 5, 6, 15, 10, 7, 8, 3,
1065 unsigned char sel, cpudv0, plb2xDiv;
1067 mfcpr(cpr0_plld, tmp);
1070 * Determine forward divider A
1072 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1075 * Determine FBK_DIV.
1077 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1082 sysInfo->pllPlbDiv = 2;
1087 mfcpr(cpr0_perd, tmp);
1088 tmp = (tmp >> 24) & 0x03;
1089 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1094 mfcpr(cpr0_opbd, tmp);
1095 tmp = (tmp >> 24) & 0x03;
1096 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1098 /* Determine PLB2XDV0 */
1099 mfcpr(cpr0_plbd, tmp);
1100 tmp = (tmp >> 16) & 0x07;
1101 plb2xDiv = (tmp == 0) ? 8 : tmp;
1103 /* Determine CPUDV0 */
1104 mfcpr(cpr0_cpud, tmp);
1105 tmp = (tmp >> 24) & 0x07;
1106 cpudv0 = (tmp == 0) ? 8 : tmp;
1108 /* Determine SEL(5:7) in CPR0_PLLC */
1109 mfcpr(cpr0_pllc, tmp);
1110 sel = (tmp >> 24) & 0x07;
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
1121 m = sysInfo->pllFwdDiv * cpudv0;
1123 case PLL_FBK_PERCLK:
1124 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1125 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1127 case PLL_FBK_PLL_LOCAL:
1130 printf("%s unknown m\n", __FUNCTION__);
1134 m *= sysInfo->pllFbkDiv;
1137 * Determine VCO clock frequency
1139 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1140 (unsigned long long)sysClkPeriodPs;
1143 * Determine CPU clock frequency
1145 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1148 * Determine PLB clock frequency, ddr1x should be the same
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;
1157 /********************************************
1159 * return OPB bus freq in Hz
1160 *********************************************/
1161 ulong get_OPB_freq (void)
1165 PPC4xx_SYS_INFO sys_info;
1167 get_sys_info (&sys_info);
1168 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1175 int get_clocks (void)
1177 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1178 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1179 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1181 sys_info_t sys_info;
1183 get_sys_info (&sys_info);
1184 gd->cpu_clk = sys_info.freqProcessor;
1185 gd->bus_clk = sys_info.freqPLB;
1187 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1189 #ifdef CONFIG_IOP480
1190 gd->cpu_clk = 66000000;
1191 gd->bus_clk = 66000000;
1197 /********************************************
1199 * return PLB bus freq in Hz
1200 *********************************************/
1201 ulong get_bus_freq (ulong dummy)
1205 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1206 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1207 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1209 sys_info_t sys_info;
1211 get_sys_info (&sys_info);
1212 val = sys_info.freqPLB;
1214 #elif defined(CONFIG_IOP480)
1219 # error get_bus_freq() not implemented