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(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( sdr_sdstp0,strp0 );
488 mfsdr( sdr_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(sdr_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;
919 * Read PLL Mode registers
921 mfcpr(cprplld, cpr_plld);
922 mfcpr(cprpllc, cpr_pllc);
925 * Determine forward divider A
927 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
930 * Determine forward divider B
932 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
933 if (sysInfo->pllFwdDivB == 0)
934 sysInfo->pllFwdDivB = 8;
939 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
940 if (sysInfo->pllFbkDiv == 0)
941 sysInfo->pllFbkDiv = 256;
944 * Read CPR_PRIMAD register
946 mfcpr(cprprimad, cpr_primad);
951 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
952 if (sysInfo->pllPlbDiv == 0)
953 sysInfo->pllPlbDiv = 16;
956 * Determine EXTBUS_DIV.
958 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
959 if (sysInfo->pllExtBusDiv == 0)
960 sysInfo->pllExtBusDiv = 16;
965 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
966 if (sysInfo->pllOpbDiv == 0)
967 sysInfo->pllOpbDiv = 16;
970 * Determine the M factor
972 if (cpr_pllc & PLLC_SRC_MASK)
973 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
975 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
978 * Determine VCO clock frequency
980 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
981 (unsigned long long)sysClkPeriodPs;
984 * Determine CPU clock frequency
986 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
987 if (primad_cpudv == 0)
990 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
991 sysInfo->pllFwdDiv / primad_cpudv;
994 * Determine PLB clock frequency
996 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
997 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
999 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1000 sysInfo->pllExtBusDiv;
1002 sysInfo->freqUART = sysInfo->freqVCOHz;
1005 /********************************************
1007 * return OPB bus freq in Hz
1008 *********************************************/
1009 ulong get_OPB_freq (void)
1013 PPC4xx_SYS_INFO sys_info;
1015 get_sys_info (&sys_info);
1016 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1021 #elif defined(CONFIG_405EX)
1024 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1025 * We need the specs!!!!
1027 static unsigned char get_fbdv(unsigned char index)
1029 unsigned char ret = 0;
1030 /* This is table should be 256 bytes.
1031 * Only take first 52 values.
1033 unsigned char fbdv_tb[] = {
1034 0x00, 0xff, 0x7f, 0xfd,
1035 0x7a, 0xf5, 0x6a, 0xd5,
1036 0x2a, 0xd4, 0x29, 0xd3,
1037 0x26, 0xcc, 0x19, 0xb3,
1038 0x67, 0xce, 0x1d, 0xbb,
1039 0x77, 0xee, 0x5d, 0xba,
1040 0x74, 0xe9, 0x52, 0xa5,
1041 0x4b, 0x96, 0x2c, 0xd8,
1042 0x31, 0xe3, 0x46, 0x8d,
1043 0x1b, 0xb7, 0x6f, 0xde,
1044 0x3d, 0xfb, 0x76, 0xed,
1045 0x5a, 0xb5, 0x6b, 0xd6,
1046 0x2d, 0xdb, 0x36, 0xec,
1050 if ((index & 0x7f) == 0)
1052 while (ret < sizeof (fbdv_tb)) {
1053 if (fbdv_tb[ret] == index)
1062 #define PLL_FBK_PLL_LOCAL 0
1063 #define PLL_FBK_CPU 1
1064 #define PLL_FBK_PERCLK 5
1066 void get_sys_info (sys_info_t * sysInfo)
1068 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1069 unsigned long m = 1;
1071 unsigned char fwdva[16] = {
1072 1, 2, 14, 9, 4, 11, 16, 13,
1073 12, 5, 6, 15, 10, 7, 8, 3,
1075 unsigned char sel, cpudv0, plb2xDiv;
1077 mfcpr(cpr0_plld, tmp);
1080 * Determine forward divider A
1082 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1085 * Determine FBK_DIV.
1087 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1092 sysInfo->pllPlbDiv = 2;
1097 mfcpr(cpr0_perd, tmp);
1098 tmp = (tmp >> 24) & 0x03;
1099 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1104 mfcpr(cpr0_opbd, tmp);
1105 tmp = (tmp >> 24) & 0x03;
1106 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1108 /* Determine PLB2XDV0 */
1109 mfcpr(cpr0_plbd, tmp);
1110 tmp = (tmp >> 16) & 0x07;
1111 plb2xDiv = (tmp == 0) ? 8 : tmp;
1113 /* Determine CPUDV0 */
1114 mfcpr(cpr0_cpud, tmp);
1115 tmp = (tmp >> 24) & 0x07;
1116 cpudv0 = (tmp == 0) ? 8 : tmp;
1118 /* Determine SEL(5:7) in CPR0_PLLC */
1119 mfcpr(cpr0_pllc, tmp);
1120 sel = (tmp >> 24) & 0x07;
1123 * Determine the M factor
1124 * PLL local: M = FBDV
1125 * CPU clock: M = FBDV * FWDVA * CPUDV0
1126 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1131 m = sysInfo->pllFwdDiv * cpudv0;
1133 case PLL_FBK_PERCLK:
1134 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1135 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1137 case PLL_FBK_PLL_LOCAL:
1140 printf("%s unknown m\n", __FUNCTION__);
1144 m *= sysInfo->pllFbkDiv;
1147 * Determine VCO clock frequency
1149 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1150 (unsigned long long)sysClkPeriodPs;
1153 * Determine CPU clock frequency
1155 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1158 * Determine PLB clock frequency, ddr1x should be the same
1160 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1161 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1162 sysInfo->freqDDR = sysInfo->freqPLB;
1163 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1164 sysInfo->freqUART = sysInfo->freqPLB;
1167 /********************************************
1169 * return OPB bus freq in Hz
1170 *********************************************/
1171 ulong get_OPB_freq (void)
1175 PPC4xx_SYS_INFO sys_info;
1177 get_sys_info (&sys_info);
1178 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1185 int get_clocks (void)
1187 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1191 sys_info_t sys_info;
1193 get_sys_info (&sys_info);
1194 gd->cpu_clk = sys_info.freqProcessor;
1195 gd->bus_clk = sys_info.freqPLB;
1197 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1199 #ifdef CONFIG_IOP480
1200 gd->cpu_clk = 66000000;
1201 gd->bus_clk = 66000000;
1207 /********************************************
1209 * return PLB bus freq in Hz
1210 *********************************************/
1211 ulong get_bus_freq (ulong dummy)
1215 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1216 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1217 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1219 sys_info_t sys_info;
1221 get_sys_info (&sys_info);
1222 val = sys_info.freqPLB;
1224 #elif defined(CONFIG_IOP480)
1229 # error get_bus_freq() not implemented