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->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
169 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
170 sysInfo->freqUART = sysInfo->freqProcessor;
174 /********************************************
176 * return PCI bus freq in Hz
177 *********************************************/
178 ulong get_PCI_freq (void)
181 PPC4xx_SYS_INFO sys_info;
183 get_sys_info (&sys_info);
184 val = sys_info.freqPLB / sys_info.pllPciDiv;
189 #elif defined(CONFIG_440)
191 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
192 defined(CONFIG_460SX)
193 static u8 pll_fwdv_multi_bits[] = {
194 /* values for: 1 - 16 */
195 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
196 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
199 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
203 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
204 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
210 static u8 pll_fbdv_multi_bits[] = {
211 /* values for: 1 - 100 */
212 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
213 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
214 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
215 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
216 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
217 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
218 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
219 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
220 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
221 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
222 /* values for: 101 - 200 */
223 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
224 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
225 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
226 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
227 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
228 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
229 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
230 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
231 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
232 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
233 /* values for: 201 - 255 */
234 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
235 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
236 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
237 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
238 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
239 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
242 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
246 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
247 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
254 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
257 void get_sys_info (sys_info_t * sysInfo)
263 unsigned long plbedv0;
265 /* Extract configured divisors */
266 mfsdr(SDR0_SDSTP0, strp0);
267 mfsdr(SDR0_SDSTP1, strp1);
269 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
270 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
272 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
273 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
275 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
276 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
278 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
279 sysInfo->pllOpbDiv = temp ? temp : 4;
281 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
282 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
283 sysInfo->pllExtBusDiv = temp ? temp : 4;
285 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
286 plbedv0 = temp ? temp: 8;
288 /* Calculate 'M' based on feedback source */
289 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
291 /* PLL internal feedback */
292 m = sysInfo->pllFbkDiv;
294 /* PLL PerClk feedback */
295 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
296 sysInfo->pllExtBusDiv;
299 /* Now calculate the individual clocks */
300 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
301 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
302 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
303 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
304 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
305 sysInfo->freqDDR = sysInfo->freqPLB;
306 sysInfo->freqUART = sysInfo->freqPLB;
311 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
312 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
313 void get_sys_info (sys_info_t *sysInfo)
319 unsigned long prbdv0;
321 WARNING: ASSUMES the following:
327 /* Decode CPR0_PLLD0 for divisors */
328 mfcpr(CPR0_PLLD, reg);
329 temp = (reg & PLLD_FWDVA_MASK) >> 16;
330 sysInfo->pllFwdDivA = temp ? temp : 16;
331 temp = (reg & PLLD_FWDVB_MASK) >> 8;
332 sysInfo->pllFwdDivB = temp ? temp: 8 ;
333 temp = (reg & PLLD_FBDV_MASK) >> 24;
334 sysInfo->pllFbkDiv = temp ? temp : 32;
335 lfdiv = reg & PLLD_LFBDV_MASK;
337 mfcpr(CPR0_OPBD0, reg);
338 temp = (reg & OPBDDV_MASK) >> 24;
339 sysInfo->pllOpbDiv = temp ? temp : 4;
341 mfcpr(CPR0_PERD, reg);
342 temp = (reg & PERDV_MASK) >> 24;
343 sysInfo->pllExtBusDiv = temp ? temp : 8;
345 mfcpr(CPR0_PRIMBD0, reg);
346 temp = (reg & PRBDV_MASK) >> 24;
347 prbdv0 = temp ? temp : 8;
349 mfcpr(CPR0_SPCID, reg);
350 temp = (reg & SPCID_MASK) >> 24;
351 sysInfo->pllPciDiv = temp ? temp : 4;
353 /* Calculate 'M' based on feedback source */
354 mfsdr(SDR0_SDSTP0, reg);
355 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
356 if (temp == 0) { /* PLL output */
357 /* Figure which pll to use */
358 mfcpr(CPR0_PLLC, reg);
359 temp = (reg & PLLC_SRC_MASK) >> 29;
360 if (!temp) /* PLLOUTA */
361 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
363 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
365 else if (temp == 1) /* CPU output */
366 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
368 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
370 /* Now calculate the individual clocks */
371 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
372 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
373 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
374 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
375 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
376 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
377 sysInfo->freqUART = sysInfo->freqPLB;
379 /* Figure which timer source to use */
380 if (mfspr(SPRN_CCR1) & 0x0080) {
381 /* External Clock, assume same as SYS_CLK */
382 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
383 if (CONFIG_SYS_CLK_FREQ > temp)
384 sysInfo->freqTmrClk = temp;
386 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
388 else /* Internal clock */
389 sysInfo->freqTmrClk = sysInfo->freqProcessor;
392 /********************************************
394 * return PCI bus freq in Hz
395 *********************************************/
396 ulong get_PCI_freq (void)
399 get_sys_info (&sys_info);
400 return sys_info.freqPCI;
403 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
404 && !defined(CONFIG_XILINX_440)
405 void get_sys_info (sys_info_t * sysInfo)
411 /* Extract configured divisors */
412 strp0 = mfdcr( CPC0_STRP0 );
413 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
414 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
415 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
416 sysInfo->pllFbkDiv = temp ? temp : 16;
417 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
418 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
420 /* Calculate 'M' based on feedback source */
421 if( strp0 & PLLSYS0_EXTSL_MASK )
422 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
424 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
426 /* Now calculate the individual clocks */
427 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
428 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
429 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
430 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
431 sysInfo->freqPLB >>= 1;
432 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
433 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
434 sysInfo->freqUART = sysInfo->freqPLB;
438 #if !defined(CONFIG_XILINX_440)
439 void get_sys_info (sys_info_t * sysInfo)
447 unsigned long prbdv0;
449 #if defined(CONFIG_YUCCA)
450 unsigned long sys_freq;
451 unsigned long sys_per=0;
453 unsigned long pci_clock_per;
454 unsigned long sdr_ddrpll;
456 /*-------------------------------------------------------------------------+
457 | Get the system clock period.
458 +-------------------------------------------------------------------------*/
459 sys_per = determine_sysper();
461 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
463 /*-------------------------------------------------------------------------+
464 | Calculate the system clock speed from the period.
465 +-------------------------------------------------------------------------*/
466 sys_freq = (ONE_BILLION / sys_per) * 1000;
469 /* Extract configured divisors */
470 mfsdr( SDR0_SDSTP0,strp0 );
471 mfsdr( SDR0_SDSTP1,strp1 );
473 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
474 sysInfo->pllFwdDivA = temp ? temp : 16 ;
475 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
476 sysInfo->pllFwdDivB = temp ? temp: 8 ;
477 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
478 sysInfo->pllFbkDiv = temp ? temp : 32;
479 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
480 sysInfo->pllOpbDiv = temp ? temp : 4;
481 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
482 sysInfo->pllExtBusDiv = temp ? temp : 4;
483 prbdv0 = (strp0 >> 2) & 0x7;
485 /* Calculate 'M' based on feedback source */
486 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
487 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
488 lfdiv = temp1 ? temp1 : 64;
489 if (temp == 0) { /* PLL output */
490 /* Figure which pll to use */
491 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
493 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
495 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
497 else if (temp == 1) /* CPU output */
498 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
500 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
502 /* Now calculate the individual clocks */
503 #if defined(CONFIG_YUCCA)
504 sysInfo->freqVCOMhz = (m * sys_freq) ;
506 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
508 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
509 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
510 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
511 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
513 #if defined(CONFIG_YUCCA)
514 /* Determine PCI Clock Period */
515 pci_clock_per = determine_pci_clock_per();
516 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
517 mfsdr(SDR0_DDR0, sdr_ddrpll);
518 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
521 sysInfo->freqUART = sysInfo->freqPLB;
525 #endif /* CONFIG_XILINX_440 */
527 #if defined(CONFIG_YUCCA)
528 unsigned long determine_sysper(void)
530 unsigned int fpga_clocking_reg;
531 unsigned int master_clock_selection;
532 unsigned long master_clock_per = 0;
533 unsigned long fb_div_selection;
534 unsigned int vco_div_reg_value;
535 unsigned long vco_div_selection;
536 unsigned long sys_per = 0;
539 /*-------------------------------------------------------------------------+
540 | Read FPGA reg 0 and reg 1 to get FPGA reg information
541 +-------------------------------------------------------------------------*/
542 fpga_clocking_reg = in16(FPGA_REG16);
545 /* Determine Master Clock Source Selection */
546 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
548 switch(master_clock_selection) {
549 case FPGA_REG16_MASTER_CLK_66_66:
550 master_clock_per = PERIOD_66_66MHZ;
552 case FPGA_REG16_MASTER_CLK_50:
553 master_clock_per = PERIOD_50_00MHZ;
555 case FPGA_REG16_MASTER_CLK_33_33:
556 master_clock_per = PERIOD_33_33MHZ;
558 case FPGA_REG16_MASTER_CLK_25:
559 master_clock_per = PERIOD_25_00MHZ;
561 case FPGA_REG16_MASTER_CLK_EXT:
562 if ((extClkVal==EXTCLK_33_33)
563 && (extClkVal==EXTCLK_50)
564 && (extClkVal==EXTCLK_66_66)
565 && (extClkVal==EXTCLK_83)) {
566 /* calculate master clock period from external clock value */
567 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
570 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
576 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
581 /* Determine FB divisors values */
582 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
583 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
584 fb_div_selection = FPGA_FB_DIV_6;
586 fb_div_selection = FPGA_FB_DIV_12;
588 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
589 fb_div_selection = FPGA_FB_DIV_10;
591 fb_div_selection = FPGA_FB_DIV_20;
594 /* Determine VCO divisors values */
595 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
597 switch(vco_div_reg_value) {
598 case FPGA_REG16_VCO_DIV_4:
599 vco_div_selection = FPGA_VCO_DIV_4;
601 case FPGA_REG16_VCO_DIV_6:
602 vco_div_selection = FPGA_VCO_DIV_6;
604 case FPGA_REG16_VCO_DIV_8:
605 vco_div_selection = FPGA_VCO_DIV_8;
607 case FPGA_REG16_VCO_DIV_10:
609 vco_div_selection = FPGA_VCO_DIV_10;
613 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
614 switch(master_clock_per) {
615 case PERIOD_25_00MHZ:
616 if (fb_div_selection == FPGA_FB_DIV_12) {
617 if (vco_div_selection == FPGA_VCO_DIV_4)
618 sys_per = PERIOD_75_00MHZ;
619 if (vco_div_selection == FPGA_VCO_DIV_6)
620 sys_per = PERIOD_50_00MHZ;
623 case PERIOD_33_33MHZ:
624 if (fb_div_selection == FPGA_FB_DIV_6) {
625 if (vco_div_selection == FPGA_VCO_DIV_4)
626 sys_per = PERIOD_50_00MHZ;
627 if (vco_div_selection == FPGA_VCO_DIV_6)
628 sys_per = PERIOD_33_33MHZ;
630 if (fb_div_selection == FPGA_FB_DIV_10) {
631 if (vco_div_selection == FPGA_VCO_DIV_4)
632 sys_per = PERIOD_83_33MHZ;
633 if (vco_div_selection == FPGA_VCO_DIV_10)
634 sys_per = PERIOD_33_33MHZ;
636 if (fb_div_selection == FPGA_FB_DIV_12) {
637 if (vco_div_selection == FPGA_VCO_DIV_4)
638 sys_per = PERIOD_100_00MHZ;
639 if (vco_div_selection == FPGA_VCO_DIV_6)
640 sys_per = PERIOD_66_66MHZ;
641 if (vco_div_selection == FPGA_VCO_DIV_8)
642 sys_per = PERIOD_50_00MHZ;
645 case PERIOD_50_00MHZ:
646 if (fb_div_selection == FPGA_FB_DIV_6) {
647 if (vco_div_selection == FPGA_VCO_DIV_4)
648 sys_per = PERIOD_75_00MHZ;
649 if (vco_div_selection == FPGA_VCO_DIV_6)
650 sys_per = PERIOD_50_00MHZ;
652 if (fb_div_selection == FPGA_FB_DIV_10) {
653 if (vco_div_selection == FPGA_VCO_DIV_6)
654 sys_per = PERIOD_83_33MHZ;
655 if (vco_div_selection == FPGA_VCO_DIV_10)
656 sys_per = PERIOD_50_00MHZ;
658 if (fb_div_selection == FPGA_FB_DIV_12) {
659 if (vco_div_selection == FPGA_VCO_DIV_6)
660 sys_per = PERIOD_100_00MHZ;
661 if (vco_div_selection == FPGA_VCO_DIV_8)
662 sys_per = PERIOD_75_00MHZ;
665 case PERIOD_66_66MHZ:
666 if (fb_div_selection == FPGA_FB_DIV_6) {
667 if (vco_div_selection == FPGA_VCO_DIV_4)
668 sys_per = PERIOD_100_00MHZ;
669 if (vco_div_selection == FPGA_VCO_DIV_6)
670 sys_per = PERIOD_66_66MHZ;
671 if (vco_div_selection == FPGA_VCO_DIV_8)
672 sys_per = PERIOD_50_00MHZ;
674 if (fb_div_selection == FPGA_FB_DIV_10) {
675 if (vco_div_selection == FPGA_VCO_DIV_8)
676 sys_per = PERIOD_83_33MHZ;
677 if (vco_div_selection == FPGA_VCO_DIV_10)
678 sys_per = PERIOD_66_66MHZ;
680 if (fb_div_selection == FPGA_FB_DIV_12) {
681 if (vco_div_selection == FPGA_VCO_DIV_8)
682 sys_per = PERIOD_100_00MHZ;
690 /* Other combinations are not supported */
691 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
695 /* calcul system clock without cheking */
696 /* if engineering option clock no check is selected */
697 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
698 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
704 /*-------------------------------------------------------------------------+
705 | determine_pci_clock_per.
706 +-------------------------------------------------------------------------*/
707 unsigned long determine_pci_clock_per(void)
709 unsigned long pci_clock_selection, pci_period;
711 /*-------------------------------------------------------------------------+
712 | Read FPGA reg 6 to get PCI 0 FPGA reg information
713 +-------------------------------------------------------------------------*/
714 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
717 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
719 switch (pci_clock_selection) {
720 case FPGA_REG16_PCI0_CLK_133_33:
721 pci_period = PERIOD_133_33MHZ;
723 case FPGA_REG16_PCI0_CLK_100:
724 pci_period = PERIOD_100_00MHZ;
726 case FPGA_REG16_PCI0_CLK_66_66:
727 pci_period = PERIOD_66_66MHZ;
730 pci_period = PERIOD_33_33MHZ;;
738 #elif defined(CONFIG_XILINX_405)
739 extern void get_sys_info (sys_info_t * sysInfo);
740 extern ulong get_PCI_freq (void);
742 #elif defined(CONFIG_AP1000)
743 void get_sys_info (sys_info_t * sysInfo)
745 sysInfo->freqProcessor = 240 * 1000 * 1000;
746 sysInfo->freqPLB = 80 * 1000 * 1000;
747 sysInfo->freqPCI = 33 * 1000 * 1000;
750 #elif defined(CONFIG_405)
752 void get_sys_info (sys_info_t * sysInfo)
754 sysInfo->freqVCOMhz=3125000;
755 sysInfo->freqProcessor=12*1000*1000;
756 sysInfo->freqPLB=50*1000*1000;
757 sysInfo->freqPCI=66*1000*1000;
760 #elif defined(CONFIG_405EP)
761 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
763 unsigned long pllmr0;
764 unsigned long pllmr1;
765 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
767 unsigned long pllmr0_ccdv;
770 * Read PLL Mode registers
772 pllmr0 = mfdcr (CPC0_PLLMR0);
773 pllmr1 = mfdcr (CPC0_PLLMR1);
776 * Determine forward divider A
778 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
781 * Determine forward divider B (should be equal to A)
783 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
788 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
789 if (sysInfo->pllFbkDiv == 0)
790 sysInfo->pllFbkDiv = 16;
795 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
800 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
803 * Determine EXTBUS_DIV.
805 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
810 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
813 * Determine the M factor
815 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
818 * Determine VCO clock frequency
820 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
821 (unsigned long long)sysClkPeriodPs;
824 * Determine CPU clock frequency
826 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
827 if (pllmr1 & PLLMR1_SSCS_MASK) {
829 * This is true if FWDVA == FWDVB:
830 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
833 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
834 / sysInfo->pllFwdDiv / pllmr0_ccdv;
836 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
840 * Determine PLB clock frequency
842 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
844 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
846 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
848 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
852 /********************************************
854 * return PCI bus freq in Hz
855 *********************************************/
856 ulong get_PCI_freq (void)
859 PPC4xx_SYS_INFO sys_info;
861 get_sys_info (&sys_info);
862 val = sys_info.freqPLB / sys_info.pllPciDiv;
866 #elif defined(CONFIG_405EZ)
867 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
869 unsigned long cpr_plld;
870 unsigned long cpr_pllc;
871 unsigned long cpr_primad;
872 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
873 unsigned long primad_cpudv;
875 unsigned long plloutb;
878 * Read PLL Mode registers
880 mfcpr(CPR0_PLLD, cpr_plld);
881 mfcpr(CPR0_PLLC, cpr_pllc);
884 * Determine forward divider A
886 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
889 * Determine forward divider B
891 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
892 if (sysInfo->pllFwdDivB == 0)
893 sysInfo->pllFwdDivB = 8;
898 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
899 if (sysInfo->pllFbkDiv == 0)
900 sysInfo->pllFbkDiv = 256;
903 * Read CPR_PRIMAD register
905 mfcpr(CPC0_PRIMAD, cpr_primad);
910 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
911 if (sysInfo->pllPlbDiv == 0)
912 sysInfo->pllPlbDiv = 16;
915 * Determine EXTBUS_DIV.
917 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
918 if (sysInfo->pllExtBusDiv == 0)
919 sysInfo->pllExtBusDiv = 16;
924 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
925 if (sysInfo->pllOpbDiv == 0)
926 sysInfo->pllOpbDiv = 16;
929 * Determine the M factor
931 if (cpr_pllc & PLLC_SRC_MASK)
932 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
934 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
937 * Determine VCO clock frequency
939 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
940 (unsigned long long)sysClkPeriodPs;
943 * Determine CPU clock frequency
945 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
946 if (primad_cpudv == 0)
949 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
950 sysInfo->pllFwdDiv / primad_cpudv;
953 * Determine PLB clock frequency
955 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
956 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
958 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
961 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
962 sysInfo->pllExtBusDiv;
964 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
965 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
966 sysInfo->pllFwdDivB);
967 sysInfo->freqUART = plloutb;
970 #elif defined(CONFIG_405EX)
973 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
974 * We need the specs!!!!
976 static unsigned char get_fbdv(unsigned char index)
978 unsigned char ret = 0;
979 /* This is table should be 256 bytes.
980 * Only take first 52 values.
982 unsigned char fbdv_tb[] = {
983 0x00, 0xff, 0x7f, 0xfd,
984 0x7a, 0xf5, 0x6a, 0xd5,
985 0x2a, 0xd4, 0x29, 0xd3,
986 0x26, 0xcc, 0x19, 0xb3,
987 0x67, 0xce, 0x1d, 0xbb,
988 0x77, 0xee, 0x5d, 0xba,
989 0x74, 0xe9, 0x52, 0xa5,
990 0x4b, 0x96, 0x2c, 0xd8,
991 0x31, 0xe3, 0x46, 0x8d,
992 0x1b, 0xb7, 0x6f, 0xde,
993 0x3d, 0xfb, 0x76, 0xed,
994 0x5a, 0xb5, 0x6b, 0xd6,
995 0x2d, 0xdb, 0x36, 0xec,
999 if ((index & 0x7f) == 0)
1001 while (ret < sizeof (fbdv_tb)) {
1002 if (fbdv_tb[ret] == index)
1011 #define PLL_FBK_PLL_LOCAL 0
1012 #define PLL_FBK_CPU 1
1013 #define PLL_FBK_PERCLK 5
1015 void get_sys_info (sys_info_t * sysInfo)
1017 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1018 unsigned long m = 1;
1020 unsigned char fwdva[16] = {
1021 1, 2, 14, 9, 4, 11, 16, 13,
1022 12, 5, 6, 15, 10, 7, 8, 3,
1024 unsigned char sel, cpudv0, plb2xDiv;
1026 mfcpr(CPR0_PLLD, tmp);
1029 * Determine forward divider A
1031 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1034 * Determine FBK_DIV.
1036 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1041 sysInfo->pllPlbDiv = 2;
1046 mfcpr(CPR0_PERD, tmp);
1047 tmp = (tmp >> 24) & 0x03;
1048 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1053 mfcpr(CPR0_OPBD0, tmp);
1054 tmp = (tmp >> 24) & 0x03;
1055 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1057 /* Determine PLB2XDV0 */
1058 mfcpr(CPR0_PLBD, tmp);
1059 tmp = (tmp >> 16) & 0x07;
1060 plb2xDiv = (tmp == 0) ? 8 : tmp;
1062 /* Determine CPUDV0 */
1063 mfcpr(CPR0_CPUD, tmp);
1064 tmp = (tmp >> 24) & 0x07;
1065 cpudv0 = (tmp == 0) ? 8 : tmp;
1067 /* Determine SEL(5:7) in CPR0_PLLC */
1068 mfcpr(CPR0_PLLC, tmp);
1069 sel = (tmp >> 24) & 0x07;
1072 * Determine the M factor
1073 * PLL local: M = FBDV
1074 * CPU clock: M = FBDV * FWDVA * CPUDV0
1075 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1080 m = sysInfo->pllFwdDiv * cpudv0;
1082 case PLL_FBK_PERCLK:
1083 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1084 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1086 case PLL_FBK_PLL_LOCAL:
1089 printf("%s unknown m\n", __FUNCTION__);
1093 m *= sysInfo->pllFbkDiv;
1096 * Determine VCO clock frequency
1098 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1099 (unsigned long long)sysClkPeriodPs;
1102 * Determine CPU clock frequency
1104 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1107 * Determine PLB clock frequency, ddr1x should be the same
1109 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1110 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1111 sysInfo->freqDDR = sysInfo->freqPLB;
1112 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1113 sysInfo->freqUART = sysInfo->freqPLB;
1118 int get_clocks (void)
1120 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1121 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1122 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1124 sys_info_t sys_info;
1126 get_sys_info (&sys_info);
1127 gd->cpu_clk = sys_info.freqProcessor;
1128 gd->bus_clk = sys_info.freqPLB;
1130 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1132 #ifdef CONFIG_IOP480
1133 gd->cpu_clk = 66000000;
1134 gd->bus_clk = 66000000;
1140 /********************************************
1142 * return PLB bus freq in Hz
1143 *********************************************/
1144 ulong get_bus_freq (ulong dummy)
1148 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1149 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1150 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1152 sys_info_t sys_info;
1154 get_sys_info (&sys_info);
1155 val = sys_info.freqPLB;
1157 #elif defined(CONFIG_IOP480)
1162 # error get_bus_freq() not implemented
1168 #if !defined(CONFIG_IOP480)
1169 ulong get_OPB_freq (void)
1171 PPC4xx_SYS_INFO sys_info;
1173 get_sys_info (&sys_info);
1175 return sys_info.freqOPB;