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 && !defined(CONFIG_XILINX_440)
421 void get_sys_info (sys_info_t * sysInfo)
427 /* Extract configured divisors */
428 strp0 = mfdcr( cpc0_strp0 );
429 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
430 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
431 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
432 sysInfo->pllFbkDiv = temp ? temp : 16;
433 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
434 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
436 /* Calculate 'M' based on feedback source */
437 if( strp0 & PLLSYS0_EXTSL_MASK )
438 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
440 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
442 /* Now calculate the individual clocks */
443 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
444 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
445 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
446 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
447 sysInfo->freqPLB >>= 1;
448 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
449 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
450 sysInfo->freqUART = sysInfo->freqPLB;
454 #if !defined(CONFIG_XILINX_440)
455 void get_sys_info (sys_info_t * sysInfo)
463 unsigned long prbdv0;
465 #if defined(CONFIG_YUCCA)
466 unsigned long sys_freq;
467 unsigned long sys_per=0;
469 unsigned long pci_clock_per;
470 unsigned long sdr_ddrpll;
472 /*-------------------------------------------------------------------------+
473 | Get the system clock period.
474 +-------------------------------------------------------------------------*/
475 sys_per = determine_sysper();
477 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
479 /*-------------------------------------------------------------------------+
480 | Calculate the system clock speed from the period.
481 +-------------------------------------------------------------------------*/
482 sys_freq = (ONE_BILLION / sys_per) * 1000;
485 /* Extract configured divisors */
486 mfsdr( sdr_sdstp0,strp0 );
487 mfsdr( sdr_sdstp1,strp1 );
489 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
490 sysInfo->pllFwdDivA = temp ? temp : 16 ;
491 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
492 sysInfo->pllFwdDivB = temp ? temp: 8 ;
493 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
494 sysInfo->pllFbkDiv = temp ? temp : 32;
495 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
496 sysInfo->pllOpbDiv = temp ? temp : 4;
497 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
498 sysInfo->pllExtBusDiv = temp ? temp : 4;
499 prbdv0 = (strp0 >> 2) & 0x7;
501 /* Calculate 'M' based on feedback source */
502 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
503 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
504 lfdiv = temp1 ? temp1 : 64;
505 if (temp == 0) { /* PLL output */
506 /* Figure which pll to use */
507 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
509 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
511 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
513 else if (temp == 1) /* CPU output */
514 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
516 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
518 /* Now calculate the individual clocks */
519 #if defined(CONFIG_YUCCA)
520 sysInfo->freqVCOMhz = (m * sys_freq) ;
522 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
524 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
525 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
526 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
527 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
529 #if defined(CONFIG_YUCCA)
530 /* Determine PCI Clock Period */
531 pci_clock_per = determine_pci_clock_per();
532 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
533 mfsdr(sdr_ddr0, sdr_ddrpll);
534 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
537 sysInfo->freqUART = sysInfo->freqPLB;
541 #endif /* CONFIG_XILINX_440 */
543 #if defined(CONFIG_YUCCA)
544 unsigned long determine_sysper(void)
546 unsigned int fpga_clocking_reg;
547 unsigned int master_clock_selection;
548 unsigned long master_clock_per = 0;
549 unsigned long fb_div_selection;
550 unsigned int vco_div_reg_value;
551 unsigned long vco_div_selection;
552 unsigned long sys_per = 0;
555 /*-------------------------------------------------------------------------+
556 | Read FPGA reg 0 and reg 1 to get FPGA reg information
557 +-------------------------------------------------------------------------*/
558 fpga_clocking_reg = in16(FPGA_REG16);
561 /* Determine Master Clock Source Selection */
562 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
564 switch(master_clock_selection) {
565 case FPGA_REG16_MASTER_CLK_66_66:
566 master_clock_per = PERIOD_66_66MHZ;
568 case FPGA_REG16_MASTER_CLK_50:
569 master_clock_per = PERIOD_50_00MHZ;
571 case FPGA_REG16_MASTER_CLK_33_33:
572 master_clock_per = PERIOD_33_33MHZ;
574 case FPGA_REG16_MASTER_CLK_25:
575 master_clock_per = PERIOD_25_00MHZ;
577 case FPGA_REG16_MASTER_CLK_EXT:
578 if ((extClkVal==EXTCLK_33_33)
579 && (extClkVal==EXTCLK_50)
580 && (extClkVal==EXTCLK_66_66)
581 && (extClkVal==EXTCLK_83)) {
582 /* calculate master clock period from external clock value */
583 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
586 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
592 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
597 /* Determine FB divisors values */
598 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
599 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
600 fb_div_selection = FPGA_FB_DIV_6;
602 fb_div_selection = FPGA_FB_DIV_12;
604 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
605 fb_div_selection = FPGA_FB_DIV_10;
607 fb_div_selection = FPGA_FB_DIV_20;
610 /* Determine VCO divisors values */
611 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
613 switch(vco_div_reg_value) {
614 case FPGA_REG16_VCO_DIV_4:
615 vco_div_selection = FPGA_VCO_DIV_4;
617 case FPGA_REG16_VCO_DIV_6:
618 vco_div_selection = FPGA_VCO_DIV_6;
620 case FPGA_REG16_VCO_DIV_8:
621 vco_div_selection = FPGA_VCO_DIV_8;
623 case FPGA_REG16_VCO_DIV_10:
625 vco_div_selection = FPGA_VCO_DIV_10;
629 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
630 switch(master_clock_per) {
631 case PERIOD_25_00MHZ:
632 if (fb_div_selection == FPGA_FB_DIV_12) {
633 if (vco_div_selection == FPGA_VCO_DIV_4)
634 sys_per = PERIOD_75_00MHZ;
635 if (vco_div_selection == FPGA_VCO_DIV_6)
636 sys_per = PERIOD_50_00MHZ;
639 case PERIOD_33_33MHZ:
640 if (fb_div_selection == FPGA_FB_DIV_6) {
641 if (vco_div_selection == FPGA_VCO_DIV_4)
642 sys_per = PERIOD_50_00MHZ;
643 if (vco_div_selection == FPGA_VCO_DIV_6)
644 sys_per = PERIOD_33_33MHZ;
646 if (fb_div_selection == FPGA_FB_DIV_10) {
647 if (vco_div_selection == FPGA_VCO_DIV_4)
648 sys_per = PERIOD_83_33MHZ;
649 if (vco_div_selection == FPGA_VCO_DIV_10)
650 sys_per = PERIOD_33_33MHZ;
652 if (fb_div_selection == FPGA_FB_DIV_12) {
653 if (vco_div_selection == FPGA_VCO_DIV_4)
654 sys_per = PERIOD_100_00MHZ;
655 if (vco_div_selection == FPGA_VCO_DIV_6)
656 sys_per = PERIOD_66_66MHZ;
657 if (vco_div_selection == FPGA_VCO_DIV_8)
658 sys_per = PERIOD_50_00MHZ;
661 case PERIOD_50_00MHZ:
662 if (fb_div_selection == FPGA_FB_DIV_6) {
663 if (vco_div_selection == FPGA_VCO_DIV_4)
664 sys_per = PERIOD_75_00MHZ;
665 if (vco_div_selection == FPGA_VCO_DIV_6)
666 sys_per = PERIOD_50_00MHZ;
668 if (fb_div_selection == FPGA_FB_DIV_10) {
669 if (vco_div_selection == FPGA_VCO_DIV_6)
670 sys_per = PERIOD_83_33MHZ;
671 if (vco_div_selection == FPGA_VCO_DIV_10)
672 sys_per = PERIOD_50_00MHZ;
674 if (fb_div_selection == FPGA_FB_DIV_12) {
675 if (vco_div_selection == FPGA_VCO_DIV_6)
676 sys_per = PERIOD_100_00MHZ;
677 if (vco_div_selection == FPGA_VCO_DIV_8)
678 sys_per = PERIOD_75_00MHZ;
681 case PERIOD_66_66MHZ:
682 if (fb_div_selection == FPGA_FB_DIV_6) {
683 if (vco_div_selection == FPGA_VCO_DIV_4)
684 sys_per = PERIOD_100_00MHZ;
685 if (vco_div_selection == FPGA_VCO_DIV_6)
686 sys_per = PERIOD_66_66MHZ;
687 if (vco_div_selection == FPGA_VCO_DIV_8)
688 sys_per = PERIOD_50_00MHZ;
690 if (fb_div_selection == FPGA_FB_DIV_10) {
691 if (vco_div_selection == FPGA_VCO_DIV_8)
692 sys_per = PERIOD_83_33MHZ;
693 if (vco_div_selection == FPGA_VCO_DIV_10)
694 sys_per = PERIOD_66_66MHZ;
696 if (fb_div_selection == FPGA_FB_DIV_12) {
697 if (vco_div_selection == FPGA_VCO_DIV_8)
698 sys_per = PERIOD_100_00MHZ;
706 /* Other combinations are not supported */
707 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
711 /* calcul system clock without cheking */
712 /* if engineering option clock no check is selected */
713 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
714 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
720 /*-------------------------------------------------------------------------+
721 | determine_pci_clock_per.
722 +-------------------------------------------------------------------------*/
723 unsigned long determine_pci_clock_per(void)
725 unsigned long pci_clock_selection, pci_period;
727 /*-------------------------------------------------------------------------+
728 | Read FPGA reg 6 to get PCI 0 FPGA reg information
729 +-------------------------------------------------------------------------*/
730 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
733 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
735 switch (pci_clock_selection) {
736 case FPGA_REG16_PCI0_CLK_133_33:
737 pci_period = PERIOD_133_33MHZ;
739 case FPGA_REG16_PCI0_CLK_100:
740 pci_period = PERIOD_100_00MHZ;
742 case FPGA_REG16_PCI0_CLK_66_66:
743 pci_period = PERIOD_66_66MHZ;
746 pci_period = PERIOD_33_33MHZ;;
754 ulong get_OPB_freq (void)
758 get_sys_info (&sys_info);
759 return sys_info.freqOPB;
762 #elif defined(CONFIG_XILINX_405)
763 extern void get_sys_info (sys_info_t * sysInfo);
764 extern ulong get_PCI_freq (void);
766 #elif defined(CONFIG_AP1000)
767 void get_sys_info (sys_info_t * sysInfo)
769 sysInfo->freqProcessor = 240 * 1000 * 1000;
770 sysInfo->freqPLB = 80 * 1000 * 1000;
771 sysInfo->freqPCI = 33 * 1000 * 1000;
774 #elif defined(CONFIG_405)
776 void get_sys_info (sys_info_t * sysInfo)
778 sysInfo->freqVCOMhz=3125000;
779 sysInfo->freqProcessor=12*1000*1000;
780 sysInfo->freqPLB=50*1000*1000;
781 sysInfo->freqPCI=66*1000*1000;
784 #elif defined(CONFIG_405EP)
785 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
787 unsigned long pllmr0;
788 unsigned long pllmr1;
789 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
791 unsigned long pllmr0_ccdv;
794 * Read PLL Mode registers
796 pllmr0 = mfdcr (cpc0_pllmr0);
797 pllmr1 = mfdcr (cpc0_pllmr1);
800 * Determine forward divider A
802 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
805 * Determine forward divider B (should be equal to A)
807 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
812 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
813 if (sysInfo->pllFbkDiv == 0)
814 sysInfo->pllFbkDiv = 16;
819 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
824 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
827 * Determine EXTBUS_DIV.
829 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
834 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
837 * Determine the M factor
839 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
842 * Determine VCO clock frequency
844 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
845 (unsigned long long)sysClkPeriodPs;
848 * Determine CPU clock frequency
850 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
851 if (pllmr1 & PLLMR1_SSCS_MASK) {
853 * This is true if FWDVA == FWDVB:
854 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
857 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
858 / sysInfo->pllFwdDiv / pllmr0_ccdv;
860 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
864 * Determine PLB clock frequency
866 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
868 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
870 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
874 /********************************************
876 * return OPB bus freq in Hz
877 *********************************************/
878 ulong get_OPB_freq (void)
882 PPC4xx_SYS_INFO sys_info;
884 get_sys_info (&sys_info);
885 val = sys_info.freqPLB / sys_info.pllOpbDiv;
891 /********************************************
893 * return PCI bus freq in Hz
894 *********************************************/
895 ulong get_PCI_freq (void)
898 PPC4xx_SYS_INFO sys_info;
900 get_sys_info (&sys_info);
901 val = sys_info.freqPLB / sys_info.pllPciDiv;
905 #elif defined(CONFIG_405EZ)
906 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
908 unsigned long cpr_plld;
909 unsigned long cpr_pllc;
910 unsigned long cpr_primad;
911 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
912 unsigned long primad_cpudv;
916 * Read PLL Mode registers
918 mfcpr(cprplld, cpr_plld);
919 mfcpr(cprpllc, cpr_pllc);
922 * Determine forward divider A
924 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
927 * Determine forward divider B
929 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
930 if (sysInfo->pllFwdDivB == 0)
931 sysInfo->pllFwdDivB = 8;
936 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
937 if (sysInfo->pllFbkDiv == 0)
938 sysInfo->pllFbkDiv = 256;
941 * Read CPR_PRIMAD register
943 mfcpr(cprprimad, cpr_primad);
948 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
949 if (sysInfo->pllPlbDiv == 0)
950 sysInfo->pllPlbDiv = 16;
953 * Determine EXTBUS_DIV.
955 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
956 if (sysInfo->pllExtBusDiv == 0)
957 sysInfo->pllExtBusDiv = 16;
962 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
963 if (sysInfo->pllOpbDiv == 0)
964 sysInfo->pllOpbDiv = 16;
967 * Determine the M factor
969 if (cpr_pllc & PLLC_SRC_MASK)
970 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
972 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
975 * Determine VCO clock frequency
977 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
978 (unsigned long long)sysClkPeriodPs;
981 * Determine CPU clock frequency
983 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
984 if (primad_cpudv == 0)
987 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
988 sysInfo->pllFwdDiv / primad_cpudv;
991 * Determine PLB clock frequency
993 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
994 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
996 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
997 sysInfo->pllExtBusDiv;
999 sysInfo->freqUART = sysInfo->freqVCOHz;
1002 /********************************************
1004 * return OPB bus freq in Hz
1005 *********************************************/
1006 ulong get_OPB_freq (void)
1010 PPC4xx_SYS_INFO sys_info;
1012 get_sys_info (&sys_info);
1013 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1018 #elif defined(CONFIG_405EX)
1021 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1022 * We need the specs!!!!
1024 static unsigned char get_fbdv(unsigned char index)
1026 unsigned char ret = 0;
1027 /* This is table should be 256 bytes.
1028 * Only take first 52 values.
1030 unsigned char fbdv_tb[] = {
1031 0x00, 0xff, 0x7f, 0xfd,
1032 0x7a, 0xf5, 0x6a, 0xd5,
1033 0x2a, 0xd4, 0x29, 0xd3,
1034 0x26, 0xcc, 0x19, 0xb3,
1035 0x67, 0xce, 0x1d, 0xbb,
1036 0x77, 0xee, 0x5d, 0xba,
1037 0x74, 0xe9, 0x52, 0xa5,
1038 0x4b, 0x96, 0x2c, 0xd8,
1039 0x31, 0xe3, 0x46, 0x8d,
1040 0x1b, 0xb7, 0x6f, 0xde,
1041 0x3d, 0xfb, 0x76, 0xed,
1042 0x5a, 0xb5, 0x6b, 0xd6,
1043 0x2d, 0xdb, 0x36, 0xec,
1047 if ((index & 0x7f) == 0)
1049 while (ret < sizeof (fbdv_tb)) {
1050 if (fbdv_tb[ret] == index)
1059 #define PLL_FBK_PLL_LOCAL 0
1060 #define PLL_FBK_CPU 1
1061 #define PLL_FBK_PERCLK 5
1063 void get_sys_info (sys_info_t * sysInfo)
1065 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1066 unsigned long m = 1;
1068 unsigned char fwdva[16] = {
1069 1, 2, 14, 9, 4, 11, 16, 13,
1070 12, 5, 6, 15, 10, 7, 8, 3,
1072 unsigned char sel, cpudv0, plb2xDiv;
1074 mfcpr(cpr0_plld, tmp);
1077 * Determine forward divider A
1079 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1082 * Determine FBK_DIV.
1084 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1089 sysInfo->pllPlbDiv = 2;
1094 mfcpr(cpr0_perd, tmp);
1095 tmp = (tmp >> 24) & 0x03;
1096 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1101 mfcpr(cpr0_opbd, tmp);
1102 tmp = (tmp >> 24) & 0x03;
1103 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1105 /* Determine PLB2XDV0 */
1106 mfcpr(cpr0_plbd, tmp);
1107 tmp = (tmp >> 16) & 0x07;
1108 plb2xDiv = (tmp == 0) ? 8 : tmp;
1110 /* Determine CPUDV0 */
1111 mfcpr(cpr0_cpud, tmp);
1112 tmp = (tmp >> 24) & 0x07;
1113 cpudv0 = (tmp == 0) ? 8 : tmp;
1115 /* Determine SEL(5:7) in CPR0_PLLC */
1116 mfcpr(cpr0_pllc, tmp);
1117 sel = (tmp >> 24) & 0x07;
1120 * Determine the M factor
1121 * PLL local: M = FBDV
1122 * CPU clock: M = FBDV * FWDVA * CPUDV0
1123 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1128 m = sysInfo->pllFwdDiv * cpudv0;
1130 case PLL_FBK_PERCLK:
1131 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1132 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1134 case PLL_FBK_PLL_LOCAL:
1137 printf("%s unknown m\n", __FUNCTION__);
1141 m *= sysInfo->pllFbkDiv;
1144 * Determine VCO clock frequency
1146 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1147 (unsigned long long)sysClkPeriodPs;
1150 * Determine CPU clock frequency
1152 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1155 * Determine PLB clock frequency, ddr1x should be the same
1157 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1158 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1159 sysInfo->freqDDR = sysInfo->freqPLB;
1160 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1161 sysInfo->freqUART = sysInfo->freqPLB;
1164 /********************************************
1166 * return OPB bus freq in Hz
1167 *********************************************/
1168 ulong get_OPB_freq (void)
1172 PPC4xx_SYS_INFO sys_info;
1174 get_sys_info (&sys_info);
1175 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1182 int get_clocks (void)
1184 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1185 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1186 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1188 sys_info_t sys_info;
1190 get_sys_info (&sys_info);
1191 gd->cpu_clk = sys_info.freqProcessor;
1192 gd->bus_clk = sys_info.freqPLB;
1194 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1196 #ifdef CONFIG_IOP480
1197 gd->cpu_clk = 66000000;
1198 gd->bus_clk = 66000000;
1204 /********************************************
1206 * return PLB bus freq in Hz
1207 *********************************************/
1208 ulong get_bus_freq (ulong dummy)
1212 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1213 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1214 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1216 sys_info_t sys_info;
1218 get_sys_info (&sys_info);
1219 val = sys_info.freqPLB;
1221 #elif defined(CONFIG_IOP480)
1226 # error get_bus_freq() not implemented