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->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
170 sysInfo->freqUART = sysInfo->freqProcessor;
174 /********************************************
176 * return OPB bus freq in Hz
177 *********************************************/
178 ulong get_OPB_freq (void)
182 PPC4xx_SYS_INFO sys_info;
184 get_sys_info (&sys_info);
185 val = sys_info.freqPLB / sys_info.pllOpbDiv;
191 /********************************************
193 * return PCI bus freq in Hz
194 *********************************************/
195 ulong get_PCI_freq (void)
198 PPC4xx_SYS_INFO sys_info;
200 get_sys_info (&sys_info);
201 val = sys_info.freqPLB / sys_info.pllPciDiv;
206 #elif defined(CONFIG_440)
208 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
209 defined(CONFIG_460SX)
210 static u8 pll_fwdv_multi_bits[] = {
211 /* values for: 1 - 16 */
212 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
213 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
216 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
220 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
221 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
227 static u8 pll_fbdv_multi_bits[] = {
228 /* values for: 1 - 100 */
229 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
230 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
231 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
232 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
233 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
234 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
235 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
236 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
237 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
238 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
239 /* values for: 101 - 200 */
240 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
241 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
242 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
243 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
244 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
245 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
246 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
247 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
248 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
249 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
250 /* values for: 201 - 255 */
251 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
252 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
253 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
254 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
255 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
256 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
259 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
263 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
264 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
271 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
274 void get_sys_info (sys_info_t * sysInfo)
280 unsigned long plbedv0;
282 /* Extract configured divisors */
283 mfsdr(sdr_sdstp0, strp0);
284 mfsdr(sdr_sdstp1, strp1);
286 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
287 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
289 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
290 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
292 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
293 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
295 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
296 sysInfo->pllOpbDiv = temp ? temp : 4;
298 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
299 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
300 sysInfo->pllExtBusDiv = temp ? temp : 4;
302 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
303 plbedv0 = temp ? temp: 8;
305 /* Calculate 'M' based on feedback source */
306 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
308 /* PLL internal feedback */
309 m = sysInfo->pllFbkDiv;
311 /* PLL PerClk feedback */
312 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
313 sysInfo->pllExtBusDiv;
316 /* Now calculate the individual clocks */
317 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
318 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
319 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
320 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
321 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
322 sysInfo->freqDDR = sysInfo->freqPLB;
323 sysInfo->freqUART = sysInfo->freqPLB;
328 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
329 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
330 void get_sys_info (sys_info_t *sysInfo)
336 unsigned long prbdv0;
338 WARNING: ASSUMES the following:
344 /* Decode CPR0_PLLD0 for divisors */
345 mfcpr(clk_plld, reg);
346 temp = (reg & PLLD_FWDVA_MASK) >> 16;
347 sysInfo->pllFwdDivA = temp ? temp : 16;
348 temp = (reg & PLLD_FWDVB_MASK) >> 8;
349 sysInfo->pllFwdDivB = temp ? temp: 8 ;
350 temp = (reg & PLLD_FBDV_MASK) >> 24;
351 sysInfo->pllFbkDiv = temp ? temp : 32;
352 lfdiv = reg & PLLD_LFBDV_MASK;
354 mfcpr(clk_opbd, reg);
355 temp = (reg & OPBDDV_MASK) >> 24;
356 sysInfo->pllOpbDiv = temp ? temp : 4;
358 mfcpr(clk_perd, reg);
359 temp = (reg & PERDV_MASK) >> 24;
360 sysInfo->pllExtBusDiv = temp ? temp : 8;
362 mfcpr(clk_primbd, reg);
363 temp = (reg & PRBDV_MASK) >> 24;
364 prbdv0 = temp ? temp : 8;
366 mfcpr(clk_spcid, reg);
367 temp = (reg & SPCID_MASK) >> 24;
368 sysInfo->pllPciDiv = temp ? temp : 4;
370 /* Calculate 'M' based on feedback source */
371 mfsdr(sdr_sdstp0, reg);
372 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
373 if (temp == 0) { /* PLL output */
374 /* Figure which pll to use */
375 mfcpr(clk_pllc, reg);
376 temp = (reg & PLLC_SRC_MASK) >> 29;
377 if (!temp) /* PLLOUTA */
378 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
380 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
382 else if (temp == 1) /* CPU output */
383 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
385 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
387 /* Now calculate the individual clocks */
388 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
389 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
390 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
391 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
392 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
393 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
394 sysInfo->freqUART = sysInfo->freqPLB;
396 /* Figure which timer source to use */
397 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
398 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
399 if (CONFIG_SYS_CLK_FREQ > temp)
400 sysInfo->freqTmrClk = temp;
402 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
404 else /* Internal clock */
405 sysInfo->freqTmrClk = sysInfo->freqProcessor;
408 /********************************************
410 * return PCI bus freq in Hz
411 *********************************************/
412 ulong get_PCI_freq (void)
415 get_sys_info (&sys_info);
416 return sys_info.freqPCI;
419 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
420 void get_sys_info (sys_info_t * sysInfo)
426 /* Extract configured divisors */
427 strp0 = mfdcr( cpc0_strp0 );
428 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
429 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
430 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
431 sysInfo->pllFbkDiv = temp ? temp : 16;
432 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
433 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
435 /* Calculate 'M' based on feedback source */
436 if( strp0 & PLLSYS0_EXTSL_MASK )
437 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
439 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
441 /* Now calculate the individual clocks */
442 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
443 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
444 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
445 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
446 sysInfo->freqPLB >>= 1;
447 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
448 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
449 sysInfo->freqUART = sysInfo->freqPLB;
452 void get_sys_info (sys_info_t * sysInfo)
460 unsigned long prbdv0;
462 #if defined(CONFIG_YUCCA)
463 unsigned long sys_freq;
464 unsigned long sys_per=0;
466 unsigned long pci_clock_per;
467 unsigned long sdr_ddrpll;
469 /*-------------------------------------------------------------------------+
470 | Get the system clock period.
471 +-------------------------------------------------------------------------*/
472 sys_per = determine_sysper();
474 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
476 /*-------------------------------------------------------------------------+
477 | Calculate the system clock speed from the period.
478 +-------------------------------------------------------------------------*/
479 sys_freq = (ONE_BILLION / sys_per) * 1000;
482 /* Extract configured divisors */
483 mfsdr( sdr_sdstp0,strp0 );
484 mfsdr( sdr_sdstp1,strp1 );
486 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
487 sysInfo->pllFwdDivA = temp ? temp : 16 ;
488 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
489 sysInfo->pllFwdDivB = temp ? temp: 8 ;
490 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
491 sysInfo->pllFbkDiv = temp ? temp : 32;
492 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
493 sysInfo->pllOpbDiv = temp ? temp : 4;
494 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
495 sysInfo->pllExtBusDiv = temp ? temp : 4;
496 prbdv0 = (strp0 >> 2) & 0x7;
498 /* Calculate 'M' based on feedback source */
499 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
500 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
501 lfdiv = temp1 ? temp1 : 64;
502 if (temp == 0) { /* PLL output */
503 /* Figure which pll to use */
504 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
506 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
508 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
510 else if (temp == 1) /* CPU output */
511 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
513 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
515 /* Now calculate the individual clocks */
516 #if defined(CONFIG_YUCCA)
517 sysInfo->freqVCOMhz = (m * sys_freq) ;
519 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
521 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
522 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
523 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
524 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
526 #if defined(CONFIG_YUCCA)
527 /* Determine PCI Clock Period */
528 pci_clock_per = determine_pci_clock_per();
529 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
530 mfsdr(sdr_ddr0, sdr_ddrpll);
531 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
534 sysInfo->freqUART = sysInfo->freqPLB;
539 #if defined(CONFIG_YUCCA)
540 unsigned long determine_sysper(void)
542 unsigned int fpga_clocking_reg;
543 unsigned int master_clock_selection;
544 unsigned long master_clock_per = 0;
545 unsigned long fb_div_selection;
546 unsigned int vco_div_reg_value;
547 unsigned long vco_div_selection;
548 unsigned long sys_per = 0;
551 /*-------------------------------------------------------------------------+
552 | Read FPGA reg 0 and reg 1 to get FPGA reg information
553 +-------------------------------------------------------------------------*/
554 fpga_clocking_reg = in16(FPGA_REG16);
557 /* Determine Master Clock Source Selection */
558 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
560 switch(master_clock_selection) {
561 case FPGA_REG16_MASTER_CLK_66_66:
562 master_clock_per = PERIOD_66_66MHZ;
564 case FPGA_REG16_MASTER_CLK_50:
565 master_clock_per = PERIOD_50_00MHZ;
567 case FPGA_REG16_MASTER_CLK_33_33:
568 master_clock_per = PERIOD_33_33MHZ;
570 case FPGA_REG16_MASTER_CLK_25:
571 master_clock_per = PERIOD_25_00MHZ;
573 case FPGA_REG16_MASTER_CLK_EXT:
574 if ((extClkVal==EXTCLK_33_33)
575 && (extClkVal==EXTCLK_50)
576 && (extClkVal==EXTCLK_66_66)
577 && (extClkVal==EXTCLK_83)) {
578 /* calculate master clock period from external clock value */
579 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
582 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
588 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
593 /* Determine FB divisors values */
594 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
595 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
596 fb_div_selection = FPGA_FB_DIV_6;
598 fb_div_selection = FPGA_FB_DIV_12;
600 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
601 fb_div_selection = FPGA_FB_DIV_10;
603 fb_div_selection = FPGA_FB_DIV_20;
606 /* Determine VCO divisors values */
607 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
609 switch(vco_div_reg_value) {
610 case FPGA_REG16_VCO_DIV_4:
611 vco_div_selection = FPGA_VCO_DIV_4;
613 case FPGA_REG16_VCO_DIV_6:
614 vco_div_selection = FPGA_VCO_DIV_6;
616 case FPGA_REG16_VCO_DIV_8:
617 vco_div_selection = FPGA_VCO_DIV_8;
619 case FPGA_REG16_VCO_DIV_10:
621 vco_div_selection = FPGA_VCO_DIV_10;
625 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
626 switch(master_clock_per) {
627 case PERIOD_25_00MHZ:
628 if (fb_div_selection == FPGA_FB_DIV_12) {
629 if (vco_div_selection == FPGA_VCO_DIV_4)
630 sys_per = PERIOD_75_00MHZ;
631 if (vco_div_selection == FPGA_VCO_DIV_6)
632 sys_per = PERIOD_50_00MHZ;
635 case PERIOD_33_33MHZ:
636 if (fb_div_selection == FPGA_FB_DIV_6) {
637 if (vco_div_selection == FPGA_VCO_DIV_4)
638 sys_per = PERIOD_50_00MHZ;
639 if (vco_div_selection == FPGA_VCO_DIV_6)
640 sys_per = PERIOD_33_33MHZ;
642 if (fb_div_selection == FPGA_FB_DIV_10) {
643 if (vco_div_selection == FPGA_VCO_DIV_4)
644 sys_per = PERIOD_83_33MHZ;
645 if (vco_div_selection == FPGA_VCO_DIV_10)
646 sys_per = PERIOD_33_33MHZ;
648 if (fb_div_selection == FPGA_FB_DIV_12) {
649 if (vco_div_selection == FPGA_VCO_DIV_4)
650 sys_per = PERIOD_100_00MHZ;
651 if (vco_div_selection == FPGA_VCO_DIV_6)
652 sys_per = PERIOD_66_66MHZ;
653 if (vco_div_selection == FPGA_VCO_DIV_8)
654 sys_per = PERIOD_50_00MHZ;
657 case PERIOD_50_00MHZ:
658 if (fb_div_selection == FPGA_FB_DIV_6) {
659 if (vco_div_selection == FPGA_VCO_DIV_4)
660 sys_per = PERIOD_75_00MHZ;
661 if (vco_div_selection == FPGA_VCO_DIV_6)
662 sys_per = PERIOD_50_00MHZ;
664 if (fb_div_selection == FPGA_FB_DIV_10) {
665 if (vco_div_selection == FPGA_VCO_DIV_6)
666 sys_per = PERIOD_83_33MHZ;
667 if (vco_div_selection == FPGA_VCO_DIV_10)
668 sys_per = PERIOD_50_00MHZ;
670 if (fb_div_selection == FPGA_FB_DIV_12) {
671 if (vco_div_selection == FPGA_VCO_DIV_6)
672 sys_per = PERIOD_100_00MHZ;
673 if (vco_div_selection == FPGA_VCO_DIV_8)
674 sys_per = PERIOD_75_00MHZ;
677 case PERIOD_66_66MHZ:
678 if (fb_div_selection == FPGA_FB_DIV_6) {
679 if (vco_div_selection == FPGA_VCO_DIV_4)
680 sys_per = PERIOD_100_00MHZ;
681 if (vco_div_selection == FPGA_VCO_DIV_6)
682 sys_per = PERIOD_66_66MHZ;
683 if (vco_div_selection == FPGA_VCO_DIV_8)
684 sys_per = PERIOD_50_00MHZ;
686 if (fb_div_selection == FPGA_FB_DIV_10) {
687 if (vco_div_selection == FPGA_VCO_DIV_8)
688 sys_per = PERIOD_83_33MHZ;
689 if (vco_div_selection == FPGA_VCO_DIV_10)
690 sys_per = PERIOD_66_66MHZ;
692 if (fb_div_selection == FPGA_FB_DIV_12) {
693 if (vco_div_selection == FPGA_VCO_DIV_8)
694 sys_per = PERIOD_100_00MHZ;
702 /* Other combinations are not supported */
703 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
707 /* calcul system clock without cheking */
708 /* if engineering option clock no check is selected */
709 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
710 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
716 /*-------------------------------------------------------------------------+
717 | determine_pci_clock_per.
718 +-------------------------------------------------------------------------*/
719 unsigned long determine_pci_clock_per(void)
721 unsigned long pci_clock_selection, pci_period;
723 /*-------------------------------------------------------------------------+
724 | Read FPGA reg 6 to get PCI 0 FPGA reg information
725 +-------------------------------------------------------------------------*/
726 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
729 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
731 switch (pci_clock_selection) {
732 case FPGA_REG16_PCI0_CLK_133_33:
733 pci_period = PERIOD_133_33MHZ;
735 case FPGA_REG16_PCI0_CLK_100:
736 pci_period = PERIOD_100_00MHZ;
738 case FPGA_REG16_PCI0_CLK_66_66:
739 pci_period = PERIOD_66_66MHZ;
742 pci_period = PERIOD_33_33MHZ;;
750 ulong get_OPB_freq (void)
754 get_sys_info (&sys_info);
755 return sys_info.freqOPB;
758 #elif defined(CONFIG_XILINX_405)
759 extern void get_sys_info (sys_info_t * sysInfo);
760 extern ulong get_PCI_freq (void);
762 #elif defined(CONFIG_AP1000)
763 void get_sys_info (sys_info_t * sysInfo)
765 sysInfo->freqProcessor = 240 * 1000 * 1000;
766 sysInfo->freqPLB = 80 * 1000 * 1000;
767 sysInfo->freqPCI = 33 * 1000 * 1000;
770 #elif defined(CONFIG_405)
772 void get_sys_info (sys_info_t * sysInfo)
774 sysInfo->freqVCOMhz=3125000;
775 sysInfo->freqProcessor=12*1000*1000;
776 sysInfo->freqPLB=50*1000*1000;
777 sysInfo->freqPCI=66*1000*1000;
780 #elif defined(CONFIG_405EP)
781 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
783 unsigned long pllmr0;
784 unsigned long pllmr1;
785 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
787 unsigned long pllmr0_ccdv;
790 * Read PLL Mode registers
792 pllmr0 = mfdcr (cpc0_pllmr0);
793 pllmr1 = mfdcr (cpc0_pllmr1);
796 * Determine forward divider A
798 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
801 * Determine forward divider B (should be equal to A)
803 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
808 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
809 if (sysInfo->pllFbkDiv == 0)
810 sysInfo->pllFbkDiv = 16;
815 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
820 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
823 * Determine EXTBUS_DIV.
825 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
830 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
833 * Determine the M factor
835 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
838 * Determine VCO clock frequency
840 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
841 (unsigned long long)sysClkPeriodPs;
844 * Determine CPU clock frequency
846 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
847 if (pllmr1 & PLLMR1_SSCS_MASK) {
849 * This is true if FWDVA == FWDVB:
850 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
853 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
854 / sysInfo->pllFwdDiv / pllmr0_ccdv;
856 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
860 * Determine PLB clock frequency
862 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
864 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
866 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
870 /********************************************
872 * return OPB bus freq in Hz
873 *********************************************/
874 ulong get_OPB_freq (void)
878 PPC4xx_SYS_INFO sys_info;
880 get_sys_info (&sys_info);
881 val = sys_info.freqPLB / sys_info.pllOpbDiv;
887 /********************************************
889 * return PCI bus freq in Hz
890 *********************************************/
891 ulong get_PCI_freq (void)
894 PPC4xx_SYS_INFO sys_info;
896 get_sys_info (&sys_info);
897 val = sys_info.freqPLB / sys_info.pllPciDiv;
901 #elif defined(CONFIG_405EZ)
902 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
904 unsigned long cpr_plld;
905 unsigned long cpr_pllc;
906 unsigned long cpr_primad;
907 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
908 unsigned long primad_cpudv;
912 * Read PLL Mode registers
914 mfcpr(cprplld, cpr_plld);
915 mfcpr(cprpllc, cpr_pllc);
918 * Determine forward divider A
920 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
923 * Determine forward divider B
925 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
926 if (sysInfo->pllFwdDivB == 0)
927 sysInfo->pllFwdDivB = 8;
932 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
933 if (sysInfo->pllFbkDiv == 0)
934 sysInfo->pllFbkDiv = 256;
937 * Read CPR_PRIMAD register
939 mfcpr(cprprimad, cpr_primad);
944 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
945 if (sysInfo->pllPlbDiv == 0)
946 sysInfo->pllPlbDiv = 16;
949 * Determine EXTBUS_DIV.
951 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
952 if (sysInfo->pllExtBusDiv == 0)
953 sysInfo->pllExtBusDiv = 16;
958 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
959 if (sysInfo->pllOpbDiv == 0)
960 sysInfo->pllOpbDiv = 16;
963 * Determine the M factor
965 if (cpr_pllc & PLLC_SRC_MASK)
966 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
968 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
971 * Determine VCO clock frequency
973 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
974 (unsigned long long)sysClkPeriodPs;
977 * Determine CPU clock frequency
979 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
980 if (primad_cpudv == 0)
983 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
984 sysInfo->pllFwdDiv / primad_cpudv;
987 * Determine PLB clock frequency
989 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
990 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
992 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
993 sysInfo->pllExtBusDiv;
995 sysInfo->freqUART = sysInfo->freqVCOHz;
998 /********************************************
1000 * return OPB bus freq in Hz
1001 *********************************************/
1002 ulong get_OPB_freq (void)
1006 PPC4xx_SYS_INFO sys_info;
1008 get_sys_info (&sys_info);
1009 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1014 #elif defined(CONFIG_405EX)
1017 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1018 * We need the specs!!!!
1020 static unsigned char get_fbdv(unsigned char index)
1022 unsigned char ret = 0;
1023 /* This is table should be 256 bytes.
1024 * Only take first 52 values.
1026 unsigned char fbdv_tb[] = {
1027 0x00, 0xff, 0x7f, 0xfd,
1028 0x7a, 0xf5, 0x6a, 0xd5,
1029 0x2a, 0xd4, 0x29, 0xd3,
1030 0x26, 0xcc, 0x19, 0xb3,
1031 0x67, 0xce, 0x1d, 0xbb,
1032 0x77, 0xee, 0x5d, 0xba,
1033 0x74, 0xe9, 0x52, 0xa5,
1034 0x4b, 0x96, 0x2c, 0xd8,
1035 0x31, 0xe3, 0x46, 0x8d,
1036 0x1b, 0xb7, 0x6f, 0xde,
1037 0x3d, 0xfb, 0x76, 0xed,
1038 0x5a, 0xb5, 0x6b, 0xd6,
1039 0x2d, 0xdb, 0x36, 0xec,
1043 if ((index & 0x7f) == 0)
1045 while (ret < sizeof (fbdv_tb)) {
1046 if (fbdv_tb[ret] == index)
1055 #define PLL_FBK_PLL_LOCAL 0
1056 #define PLL_FBK_CPU 1
1057 #define PLL_FBK_PERCLK 5
1059 void get_sys_info (sys_info_t * sysInfo)
1061 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1062 unsigned long m = 1;
1064 unsigned char fwdva[16] = {
1065 1, 2, 14, 9, 4, 11, 16, 13,
1066 12, 5, 6, 15, 10, 7, 8, 3,
1068 unsigned char sel, cpudv0, plb2xDiv;
1070 mfcpr(cpr0_plld, tmp);
1073 * Determine forward divider A
1075 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1078 * Determine FBK_DIV.
1080 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1085 sysInfo->pllPlbDiv = 2;
1090 mfcpr(cpr0_perd, tmp);
1091 tmp = (tmp >> 24) & 0x03;
1092 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1097 mfcpr(cpr0_opbd, tmp);
1098 tmp = (tmp >> 24) & 0x03;
1099 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1101 /* Determine PLB2XDV0 */
1102 mfcpr(cpr0_plbd, tmp);
1103 tmp = (tmp >> 16) & 0x07;
1104 plb2xDiv = (tmp == 0) ? 8 : tmp;
1106 /* Determine CPUDV0 */
1107 mfcpr(cpr0_cpud, tmp);
1108 tmp = (tmp >> 24) & 0x07;
1109 cpudv0 = (tmp == 0) ? 8 : tmp;
1111 /* Determine SEL(5:7) in CPR0_PLLC */
1112 mfcpr(cpr0_pllc, tmp);
1113 sel = (tmp >> 24) & 0x07;
1116 * Determine the M factor
1117 * PLL local: M = FBDV
1118 * CPU clock: M = FBDV * FWDVA * CPUDV0
1119 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1124 m = sysInfo->pllFwdDiv * cpudv0;
1126 case PLL_FBK_PERCLK:
1127 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1128 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1130 case PLL_FBK_PLL_LOCAL:
1133 printf("%s unknown m\n", __FUNCTION__);
1137 m *= sysInfo->pllFbkDiv;
1140 * Determine VCO clock frequency
1142 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1143 (unsigned long long)sysClkPeriodPs;
1146 * Determine CPU clock frequency
1148 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1151 * Determine PLB clock frequency, ddr1x should be the same
1153 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1154 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1155 sysInfo->freqDDR = sysInfo->freqPLB;
1156 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1157 sysInfo->freqUART = sysInfo->freqPLB;
1160 /********************************************
1162 * return OPB bus freq in Hz
1163 *********************************************/
1164 ulong get_OPB_freq (void)
1168 PPC4xx_SYS_INFO sys_info;
1170 get_sys_info (&sys_info);
1171 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1178 int get_clocks (void)
1180 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1181 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1182 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1184 sys_info_t sys_info;
1186 get_sys_info (&sys_info);
1187 gd->cpu_clk = sys_info.freqProcessor;
1188 gd->bus_clk = sys_info.freqPLB;
1190 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1192 #ifdef CONFIG_IOP480
1193 gd->cpu_clk = 66000000;
1194 gd->bus_clk = 66000000;
1200 /********************************************
1202 * return PLB bus freq in Hz
1203 *********************************************/
1204 ulong get_bus_freq (ulong dummy)
1208 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1209 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1210 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1212 sys_info_t sys_info;
1214 get_sys_info (&sys_info);
1215 val = sys_info.freqPLB;
1217 #elif defined(CONFIG_IOP480)
1222 # error get_bus_freq() not implemented