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 (CPC0_PLLMR);
56 * Read Pin Strapping register
58 psr = mfdcr (CPC0_PSR);
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(SDR0_SDSTP0, strp0);
284 mfsdr(SDR0_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(CPR0_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(CPR0_OPBD, reg);
355 temp = (reg & OPBDDV_MASK) >> 24;
356 sysInfo->pllOpbDiv = temp ? temp : 4;
358 mfcpr(CPR0_PERD, reg);
359 temp = (reg & PERDV_MASK) >> 24;
360 sysInfo->pllExtBusDiv = temp ? temp : 8;
362 mfcpr(CPR0_PRIMBD, reg);
363 temp = (reg & PRBDV_MASK) >> 24;
364 prbdv0 = temp ? temp : 8;
366 mfcpr(CPR0_SPCID, reg);
367 temp = (reg & SPCID_MASK) >> 24;
368 sysInfo->pllPciDiv = temp ? temp : 4;
370 /* Calculate 'M' based on feedback source */
371 mfsdr(SDR0_SDSTP0, reg);
372 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
373 if (temp == 0) { /* PLL output */
374 /* Figure which pll to use */
375 mfcpr(CPR0_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(SPRN_CCR1) & 0x0080) {
398 /* External Clock, assume same as SYS_CLK */
399 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
400 if (CONFIG_SYS_CLK_FREQ > temp)
401 sysInfo->freqTmrClk = temp;
403 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
405 else /* Internal clock */
406 sysInfo->freqTmrClk = sysInfo->freqProcessor;
409 /********************************************
411 * return PCI bus freq in Hz
412 *********************************************/
413 ulong get_PCI_freq (void)
416 get_sys_info (&sys_info);
417 return sys_info.freqPCI;
420 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
421 && !defined(CONFIG_XILINX_440)
422 void get_sys_info (sys_info_t * sysInfo)
428 /* Extract configured divisors */
429 strp0 = mfdcr( CPC0_STRP0 );
430 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
431 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
432 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
433 sysInfo->pllFbkDiv = temp ? temp : 16;
434 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
435 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
437 /* Calculate 'M' based on feedback source */
438 if( strp0 & PLLSYS0_EXTSL_MASK )
439 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
441 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
443 /* Now calculate the individual clocks */
444 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
445 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
446 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
447 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
448 sysInfo->freqPLB >>= 1;
449 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
450 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
451 sysInfo->freqUART = sysInfo->freqPLB;
455 #if !defined(CONFIG_XILINX_440)
456 void get_sys_info (sys_info_t * sysInfo)
464 unsigned long prbdv0;
466 #if defined(CONFIG_YUCCA)
467 unsigned long sys_freq;
468 unsigned long sys_per=0;
470 unsigned long pci_clock_per;
471 unsigned long sdr_ddrpll;
473 /*-------------------------------------------------------------------------+
474 | Get the system clock period.
475 +-------------------------------------------------------------------------*/
476 sys_per = determine_sysper();
478 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
480 /*-------------------------------------------------------------------------+
481 | Calculate the system clock speed from the period.
482 +-------------------------------------------------------------------------*/
483 sys_freq = (ONE_BILLION / sys_per) * 1000;
486 /* Extract configured divisors */
487 mfsdr( SDR0_SDSTP0,strp0 );
488 mfsdr( SDR0_SDSTP1,strp1 );
490 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
491 sysInfo->pllFwdDivA = temp ? temp : 16 ;
492 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
493 sysInfo->pllFwdDivB = temp ? temp: 8 ;
494 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
495 sysInfo->pllFbkDiv = temp ? temp : 32;
496 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
497 sysInfo->pllOpbDiv = temp ? temp : 4;
498 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
499 sysInfo->pllExtBusDiv = temp ? temp : 4;
500 prbdv0 = (strp0 >> 2) & 0x7;
502 /* Calculate 'M' based on feedback source */
503 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
504 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
505 lfdiv = temp1 ? temp1 : 64;
506 if (temp == 0) { /* PLL output */
507 /* Figure which pll to use */
508 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
510 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
512 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
514 else if (temp == 1) /* CPU output */
515 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
517 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
519 /* Now calculate the individual clocks */
520 #if defined(CONFIG_YUCCA)
521 sysInfo->freqVCOMhz = (m * sys_freq) ;
523 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
525 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
526 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
527 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
528 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
530 #if defined(CONFIG_YUCCA)
531 /* Determine PCI Clock Period */
532 pci_clock_per = determine_pci_clock_per();
533 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
534 mfsdr(SDR0_DDR0, sdr_ddrpll);
535 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
538 sysInfo->freqUART = sysInfo->freqPLB;
542 #endif /* CONFIG_XILINX_440 */
544 #if defined(CONFIG_YUCCA)
545 unsigned long determine_sysper(void)
547 unsigned int fpga_clocking_reg;
548 unsigned int master_clock_selection;
549 unsigned long master_clock_per = 0;
550 unsigned long fb_div_selection;
551 unsigned int vco_div_reg_value;
552 unsigned long vco_div_selection;
553 unsigned long sys_per = 0;
556 /*-------------------------------------------------------------------------+
557 | Read FPGA reg 0 and reg 1 to get FPGA reg information
558 +-------------------------------------------------------------------------*/
559 fpga_clocking_reg = in16(FPGA_REG16);
562 /* Determine Master Clock Source Selection */
563 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
565 switch(master_clock_selection) {
566 case FPGA_REG16_MASTER_CLK_66_66:
567 master_clock_per = PERIOD_66_66MHZ;
569 case FPGA_REG16_MASTER_CLK_50:
570 master_clock_per = PERIOD_50_00MHZ;
572 case FPGA_REG16_MASTER_CLK_33_33:
573 master_clock_per = PERIOD_33_33MHZ;
575 case FPGA_REG16_MASTER_CLK_25:
576 master_clock_per = PERIOD_25_00MHZ;
578 case FPGA_REG16_MASTER_CLK_EXT:
579 if ((extClkVal==EXTCLK_33_33)
580 && (extClkVal==EXTCLK_50)
581 && (extClkVal==EXTCLK_66_66)
582 && (extClkVal==EXTCLK_83)) {
583 /* calculate master clock period from external clock value */
584 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
587 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
593 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
598 /* Determine FB divisors values */
599 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
600 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
601 fb_div_selection = FPGA_FB_DIV_6;
603 fb_div_selection = FPGA_FB_DIV_12;
605 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
606 fb_div_selection = FPGA_FB_DIV_10;
608 fb_div_selection = FPGA_FB_DIV_20;
611 /* Determine VCO divisors values */
612 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
614 switch(vco_div_reg_value) {
615 case FPGA_REG16_VCO_DIV_4:
616 vco_div_selection = FPGA_VCO_DIV_4;
618 case FPGA_REG16_VCO_DIV_6:
619 vco_div_selection = FPGA_VCO_DIV_6;
621 case FPGA_REG16_VCO_DIV_8:
622 vco_div_selection = FPGA_VCO_DIV_8;
624 case FPGA_REG16_VCO_DIV_10:
626 vco_div_selection = FPGA_VCO_DIV_10;
630 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
631 switch(master_clock_per) {
632 case PERIOD_25_00MHZ:
633 if (fb_div_selection == FPGA_FB_DIV_12) {
634 if (vco_div_selection == FPGA_VCO_DIV_4)
635 sys_per = PERIOD_75_00MHZ;
636 if (vco_div_selection == FPGA_VCO_DIV_6)
637 sys_per = PERIOD_50_00MHZ;
640 case PERIOD_33_33MHZ:
641 if (fb_div_selection == FPGA_FB_DIV_6) {
642 if (vco_div_selection == FPGA_VCO_DIV_4)
643 sys_per = PERIOD_50_00MHZ;
644 if (vco_div_selection == FPGA_VCO_DIV_6)
645 sys_per = PERIOD_33_33MHZ;
647 if (fb_div_selection == FPGA_FB_DIV_10) {
648 if (vco_div_selection == FPGA_VCO_DIV_4)
649 sys_per = PERIOD_83_33MHZ;
650 if (vco_div_selection == FPGA_VCO_DIV_10)
651 sys_per = PERIOD_33_33MHZ;
653 if (fb_div_selection == FPGA_FB_DIV_12) {
654 if (vco_div_selection == FPGA_VCO_DIV_4)
655 sys_per = PERIOD_100_00MHZ;
656 if (vco_div_selection == FPGA_VCO_DIV_6)
657 sys_per = PERIOD_66_66MHZ;
658 if (vco_div_selection == FPGA_VCO_DIV_8)
659 sys_per = PERIOD_50_00MHZ;
662 case PERIOD_50_00MHZ:
663 if (fb_div_selection == FPGA_FB_DIV_6) {
664 if (vco_div_selection == FPGA_VCO_DIV_4)
665 sys_per = PERIOD_75_00MHZ;
666 if (vco_div_selection == FPGA_VCO_DIV_6)
667 sys_per = PERIOD_50_00MHZ;
669 if (fb_div_selection == FPGA_FB_DIV_10) {
670 if (vco_div_selection == FPGA_VCO_DIV_6)
671 sys_per = PERIOD_83_33MHZ;
672 if (vco_div_selection == FPGA_VCO_DIV_10)
673 sys_per = PERIOD_50_00MHZ;
675 if (fb_div_selection == FPGA_FB_DIV_12) {
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_100_00MHZ;
678 if (vco_div_selection == FPGA_VCO_DIV_8)
679 sys_per = PERIOD_75_00MHZ;
682 case PERIOD_66_66MHZ:
683 if (fb_div_selection == FPGA_FB_DIV_6) {
684 if (vco_div_selection == FPGA_VCO_DIV_4)
685 sys_per = PERIOD_100_00MHZ;
686 if (vco_div_selection == FPGA_VCO_DIV_6)
687 sys_per = PERIOD_66_66MHZ;
688 if (vco_div_selection == FPGA_VCO_DIV_8)
689 sys_per = PERIOD_50_00MHZ;
691 if (fb_div_selection == FPGA_FB_DIV_10) {
692 if (vco_div_selection == FPGA_VCO_DIV_8)
693 sys_per = PERIOD_83_33MHZ;
694 if (vco_div_selection == FPGA_VCO_DIV_10)
695 sys_per = PERIOD_66_66MHZ;
697 if (fb_div_selection == FPGA_FB_DIV_12) {
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_100_00MHZ;
707 /* Other combinations are not supported */
708 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
712 /* calcul system clock without cheking */
713 /* if engineering option clock no check is selected */
714 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
715 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
721 /*-------------------------------------------------------------------------+
722 | determine_pci_clock_per.
723 +-------------------------------------------------------------------------*/
724 unsigned long determine_pci_clock_per(void)
726 unsigned long pci_clock_selection, pci_period;
728 /*-------------------------------------------------------------------------+
729 | Read FPGA reg 6 to get PCI 0 FPGA reg information
730 +-------------------------------------------------------------------------*/
731 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
734 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
736 switch (pci_clock_selection) {
737 case FPGA_REG16_PCI0_CLK_133_33:
738 pci_period = PERIOD_133_33MHZ;
740 case FPGA_REG16_PCI0_CLK_100:
741 pci_period = PERIOD_100_00MHZ;
743 case FPGA_REG16_PCI0_CLK_66_66:
744 pci_period = PERIOD_66_66MHZ;
747 pci_period = PERIOD_33_33MHZ;;
755 ulong get_OPB_freq (void)
759 get_sys_info (&sys_info);
760 return sys_info.freqOPB;
763 #elif defined(CONFIG_XILINX_405)
764 extern void get_sys_info (sys_info_t * sysInfo);
765 extern ulong get_PCI_freq (void);
767 #elif defined(CONFIG_AP1000)
768 void get_sys_info (sys_info_t * sysInfo)
770 sysInfo->freqProcessor = 240 * 1000 * 1000;
771 sysInfo->freqPLB = 80 * 1000 * 1000;
772 sysInfo->freqPCI = 33 * 1000 * 1000;
775 #elif defined(CONFIG_405)
777 void get_sys_info (sys_info_t * sysInfo)
779 sysInfo->freqVCOMhz=3125000;
780 sysInfo->freqProcessor=12*1000*1000;
781 sysInfo->freqPLB=50*1000*1000;
782 sysInfo->freqPCI=66*1000*1000;
785 #elif defined(CONFIG_405EP)
786 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
788 unsigned long pllmr0;
789 unsigned long pllmr1;
790 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
792 unsigned long pllmr0_ccdv;
795 * Read PLL Mode registers
797 pllmr0 = mfdcr (CPC0_PLLMR0);
798 pllmr1 = mfdcr (CPC0_PLLMR1);
801 * Determine forward divider A
803 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
806 * Determine forward divider B (should be equal to A)
808 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
813 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
814 if (sysInfo->pllFbkDiv == 0)
815 sysInfo->pllFbkDiv = 16;
820 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
825 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
828 * Determine EXTBUS_DIV.
830 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
835 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
838 * Determine the M factor
840 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
843 * Determine VCO clock frequency
845 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
846 (unsigned long long)sysClkPeriodPs;
849 * Determine CPU clock frequency
851 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
852 if (pllmr1 & PLLMR1_SSCS_MASK) {
854 * This is true if FWDVA == FWDVB:
855 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
858 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
859 / sysInfo->pllFwdDiv / pllmr0_ccdv;
861 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
865 * Determine PLB clock frequency
867 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
869 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
871 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
873 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
877 /********************************************
879 * return OPB bus freq in Hz
880 *********************************************/
881 ulong get_OPB_freq (void)
885 PPC4xx_SYS_INFO sys_info;
887 get_sys_info (&sys_info);
888 val = sys_info.freqPLB / sys_info.pllOpbDiv;
894 /********************************************
896 * return PCI bus freq in Hz
897 *********************************************/
898 ulong get_PCI_freq (void)
901 PPC4xx_SYS_INFO sys_info;
903 get_sys_info (&sys_info);
904 val = sys_info.freqPLB / sys_info.pllPciDiv;
908 #elif defined(CONFIG_405EZ)
909 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
911 unsigned long cpr_plld;
912 unsigned long cpr_pllc;
913 unsigned long cpr_primad;
914 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
915 unsigned long primad_cpudv;
917 unsigned long plloutb;
920 * Read PLL Mode registers
922 mfcpr(CPR0_PLLD, cpr_plld);
923 mfcpr(CPR0_PLLC, cpr_pllc);
926 * Determine forward divider A
928 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
931 * Determine forward divider B
933 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
934 if (sysInfo->pllFwdDivB == 0)
935 sysInfo->pllFwdDivB = 8;
940 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
941 if (sysInfo->pllFbkDiv == 0)
942 sysInfo->pllFbkDiv = 256;
945 * Read CPR_PRIMAD register
947 mfcpr(CPC0_PRIMAD, cpr_primad);
952 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
953 if (sysInfo->pllPlbDiv == 0)
954 sysInfo->pllPlbDiv = 16;
957 * Determine EXTBUS_DIV.
959 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
960 if (sysInfo->pllExtBusDiv == 0)
961 sysInfo->pllExtBusDiv = 16;
966 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
967 if (sysInfo->pllOpbDiv == 0)
968 sysInfo->pllOpbDiv = 16;
971 * Determine the M factor
973 if (cpr_pllc & PLLC_SRC_MASK)
974 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
976 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
979 * Determine VCO clock frequency
981 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
982 (unsigned long long)sysClkPeriodPs;
985 * Determine CPU clock frequency
987 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
988 if (primad_cpudv == 0)
991 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
992 sysInfo->pllFwdDiv / primad_cpudv;
995 * Determine PLB clock frequency
997 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
998 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1000 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1001 sysInfo->pllExtBusDiv;
1003 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1004 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1005 sysInfo->pllFwdDivB);
1006 sysInfo->freqUART = plloutb;
1009 /********************************************
1011 * return OPB bus freq in Hz
1012 *********************************************/
1013 ulong get_OPB_freq (void)
1017 PPC4xx_SYS_INFO sys_info;
1019 get_sys_info (&sys_info);
1020 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1025 #elif defined(CONFIG_405EX)
1028 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1029 * We need the specs!!!!
1031 static unsigned char get_fbdv(unsigned char index)
1033 unsigned char ret = 0;
1034 /* This is table should be 256 bytes.
1035 * Only take first 52 values.
1037 unsigned char fbdv_tb[] = {
1038 0x00, 0xff, 0x7f, 0xfd,
1039 0x7a, 0xf5, 0x6a, 0xd5,
1040 0x2a, 0xd4, 0x29, 0xd3,
1041 0x26, 0xcc, 0x19, 0xb3,
1042 0x67, 0xce, 0x1d, 0xbb,
1043 0x77, 0xee, 0x5d, 0xba,
1044 0x74, 0xe9, 0x52, 0xa5,
1045 0x4b, 0x96, 0x2c, 0xd8,
1046 0x31, 0xe3, 0x46, 0x8d,
1047 0x1b, 0xb7, 0x6f, 0xde,
1048 0x3d, 0xfb, 0x76, 0xed,
1049 0x5a, 0xb5, 0x6b, 0xd6,
1050 0x2d, 0xdb, 0x36, 0xec,
1054 if ((index & 0x7f) == 0)
1056 while (ret < sizeof (fbdv_tb)) {
1057 if (fbdv_tb[ret] == index)
1066 #define PLL_FBK_PLL_LOCAL 0
1067 #define PLL_FBK_CPU 1
1068 #define PLL_FBK_PERCLK 5
1070 void get_sys_info (sys_info_t * sysInfo)
1072 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1073 unsigned long m = 1;
1075 unsigned char fwdva[16] = {
1076 1, 2, 14, 9, 4, 11, 16, 13,
1077 12, 5, 6, 15, 10, 7, 8, 3,
1079 unsigned char sel, cpudv0, plb2xDiv;
1081 mfcpr(CPR0_PLLD, tmp);
1084 * Determine forward divider A
1086 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1089 * Determine FBK_DIV.
1091 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1096 sysInfo->pllPlbDiv = 2;
1101 mfcpr(CPR0_PERD, tmp);
1102 tmp = (tmp >> 24) & 0x03;
1103 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1108 mfcpr(CPR0_OPBD, tmp);
1109 tmp = (tmp >> 24) & 0x03;
1110 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1112 /* Determine PLB2XDV0 */
1113 mfcpr(CPR0_PLBD, tmp);
1114 tmp = (tmp >> 16) & 0x07;
1115 plb2xDiv = (tmp == 0) ? 8 : tmp;
1117 /* Determine CPUDV0 */
1118 mfcpr(CPR0_CPUD, tmp);
1119 tmp = (tmp >> 24) & 0x07;
1120 cpudv0 = (tmp == 0) ? 8 : tmp;
1122 /* Determine SEL(5:7) in CPR0_PLLC */
1123 mfcpr(CPR0_PLLC, tmp);
1124 sel = (tmp >> 24) & 0x07;
1127 * Determine the M factor
1128 * PLL local: M = FBDV
1129 * CPU clock: M = FBDV * FWDVA * CPUDV0
1130 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1135 m = sysInfo->pllFwdDiv * cpudv0;
1137 case PLL_FBK_PERCLK:
1138 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1139 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1141 case PLL_FBK_PLL_LOCAL:
1144 printf("%s unknown m\n", __FUNCTION__);
1148 m *= sysInfo->pllFbkDiv;
1151 * Determine VCO clock frequency
1153 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1154 (unsigned long long)sysClkPeriodPs;
1157 * Determine CPU clock frequency
1159 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1162 * Determine PLB clock frequency, ddr1x should be the same
1164 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1165 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1166 sysInfo->freqDDR = sysInfo->freqPLB;
1167 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1168 sysInfo->freqUART = sysInfo->freqPLB;
1171 /********************************************
1173 * return OPB bus freq in Hz
1174 *********************************************/
1175 ulong get_OPB_freq (void)
1179 PPC4xx_SYS_INFO sys_info;
1181 get_sys_info (&sys_info);
1182 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1189 int get_clocks (void)
1191 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1192 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1193 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1195 sys_info_t sys_info;
1197 get_sys_info (&sys_info);
1198 gd->cpu_clk = sys_info.freqProcessor;
1199 gd->bus_clk = sys_info.freqPLB;
1201 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1203 #ifdef CONFIG_IOP480
1204 gd->cpu_clk = 66000000;
1205 gd->bus_clk = 66000000;
1211 /********************************************
1213 * return PLB bus freq in Hz
1214 *********************************************/
1215 ulong get_bus_freq (ulong dummy)
1219 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1220 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1221 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1223 sys_info_t sys_info;
1225 get_sys_info (&sys_info);
1226 val = sys_info.freqPLB;
1228 #elif defined(CONFIG_IOP480)
1233 # error get_bus_freq() not implemented