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 static u8 pll_fwdv_multi_bits[] = {
210 /* values for: 1 - 16 */
211 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
212 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
215 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
219 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
220 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
226 static u8 pll_fbdv_multi_bits[] = {
227 /* values for: 1 - 100 */
228 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
229 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
230 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
231 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
232 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
233 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
234 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
235 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
236 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
237 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
238 /* values for: 101 - 200 */
239 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
240 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
241 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
242 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
243 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
244 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
245 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
246 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
247 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
248 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
249 /* values for: 201 - 255 */
250 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
251 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
252 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
253 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
254 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
255 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
258 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
262 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
263 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
270 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
273 void get_sys_info (sys_info_t * sysInfo)
279 unsigned long plbedv0;
281 /* Extract configured divisors */
282 mfsdr(sdr_sdstp0, strp0);
283 mfsdr(sdr_sdstp1, strp1);
285 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
286 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
288 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
289 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
291 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
292 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
294 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
295 sysInfo->pllOpbDiv = temp ? temp : 4;
297 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
298 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
299 sysInfo->pllExtBusDiv = temp ? temp : 4;
301 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
302 plbedv0 = temp ? temp: 8;
304 /* Calculate 'M' based on feedback source */
305 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
307 /* PLL internal feedback */
308 m = sysInfo->pllFbkDiv;
310 /* PLL PerClk feedback */
311 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
312 sysInfo->pllExtBusDiv;
315 /* Now calculate the individual clocks */
316 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
317 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
318 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
319 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
320 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
321 sysInfo->freqDDR = sysInfo->freqPLB;
322 sysInfo->freqUART = sysInfo->freqPLB;
327 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
328 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
329 void get_sys_info (sys_info_t *sysInfo)
335 unsigned long prbdv0;
337 WARNING: ASSUMES the following:
343 /* Decode CPR0_PLLD0 for divisors */
344 mfcpr(clk_plld, reg);
345 temp = (reg & PLLD_FWDVA_MASK) >> 16;
346 sysInfo->pllFwdDivA = temp ? temp : 16;
347 temp = (reg & PLLD_FWDVB_MASK) >> 8;
348 sysInfo->pllFwdDivB = temp ? temp: 8 ;
349 temp = (reg & PLLD_FBDV_MASK) >> 24;
350 sysInfo->pllFbkDiv = temp ? temp : 32;
351 lfdiv = reg & PLLD_LFBDV_MASK;
353 mfcpr(clk_opbd, reg);
354 temp = (reg & OPBDDV_MASK) >> 24;
355 sysInfo->pllOpbDiv = temp ? temp : 4;
357 mfcpr(clk_perd, reg);
358 temp = (reg & PERDV_MASK) >> 24;
359 sysInfo->pllExtBusDiv = temp ? temp : 8;
361 mfcpr(clk_primbd, reg);
362 temp = (reg & PRBDV_MASK) >> 24;
363 prbdv0 = temp ? temp : 8;
365 mfcpr(clk_spcid, reg);
366 temp = (reg & SPCID_MASK) >> 24;
367 sysInfo->pllPciDiv = temp ? temp : 4;
369 /* Calculate 'M' based on feedback source */
370 mfsdr(sdr_sdstp0, reg);
371 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
372 if (temp == 0) { /* PLL output */
373 /* Figure which pll to use */
374 mfcpr(clk_pllc, reg);
375 temp = (reg & PLLC_SRC_MASK) >> 29;
376 if (!temp) /* PLLOUTA */
377 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
379 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
381 else if (temp == 1) /* CPU output */
382 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
384 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
386 /* Now calculate the individual clocks */
387 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
388 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
389 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
390 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
391 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
392 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
393 sysInfo->freqUART = sysInfo->freqPLB;
395 /* Figure which timer source to use */
396 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
397 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
398 if (CONFIG_SYS_CLK_FREQ > temp)
399 sysInfo->freqTmrClk = temp;
401 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
403 else /* Internal clock */
404 sysInfo->freqTmrClk = sysInfo->freqProcessor;
407 /********************************************
409 * return PCI bus freq in Hz
410 *********************************************/
411 ulong get_PCI_freq (void)
414 get_sys_info (&sys_info);
415 return sys_info.freqPCI;
418 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
419 void get_sys_info (sys_info_t * sysInfo)
425 /* Extract configured divisors */
426 strp0 = mfdcr( cpc0_strp0 );
427 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
428 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
429 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
430 sysInfo->pllFbkDiv = temp ? temp : 16;
431 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
432 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
434 /* Calculate 'M' based on feedback source */
435 if( strp0 & PLLSYS0_EXTSL_MASK )
436 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
438 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
440 /* Now calculate the individual clocks */
441 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
442 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
443 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
444 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
445 sysInfo->freqPLB >>= 1;
446 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
447 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
448 sysInfo->freqUART = sysInfo->freqPLB;
451 void get_sys_info (sys_info_t * sysInfo)
459 unsigned long prbdv0;
461 #if defined(CONFIG_YUCCA)
462 unsigned long sys_freq;
463 unsigned long sys_per=0;
465 unsigned long pci_clock_per;
466 unsigned long sdr_ddrpll;
468 /*-------------------------------------------------------------------------+
469 | Get the system clock period.
470 +-------------------------------------------------------------------------*/
471 sys_per = determine_sysper();
473 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
475 /*-------------------------------------------------------------------------+
476 | Calculate the system clock speed from the period.
477 +-------------------------------------------------------------------------*/
478 sys_freq = (ONE_BILLION / sys_per) * 1000;
481 /* Extract configured divisors */
482 mfsdr( sdr_sdstp0,strp0 );
483 mfsdr( sdr_sdstp1,strp1 );
485 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
486 sysInfo->pllFwdDivA = temp ? temp : 16 ;
487 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
488 sysInfo->pllFwdDivB = temp ? temp: 8 ;
489 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
490 sysInfo->pllFbkDiv = temp ? temp : 32;
491 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
492 sysInfo->pllOpbDiv = temp ? temp : 4;
493 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
494 sysInfo->pllExtBusDiv = temp ? temp : 4;
495 prbdv0 = (strp0 >> 2) & 0x7;
497 /* Calculate 'M' based on feedback source */
498 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
499 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
500 lfdiv = temp1 ? temp1 : 64;
501 if (temp == 0) { /* PLL output */
502 /* Figure which pll to use */
503 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
505 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
507 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
509 else if (temp == 1) /* CPU output */
510 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
512 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
514 /* Now calculate the individual clocks */
515 #if defined(CONFIG_YUCCA)
516 sysInfo->freqVCOMhz = (m * sys_freq) ;
518 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
520 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
521 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
522 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
523 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
525 #if defined(CONFIG_YUCCA)
526 /* Determine PCI Clock Period */
527 pci_clock_per = determine_pci_clock_per();
528 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
529 mfsdr(sdr_ddr0, sdr_ddrpll);
530 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
533 sysInfo->freqUART = sysInfo->freqPLB;
538 #if defined(CONFIG_YUCCA)
539 unsigned long determine_sysper(void)
541 unsigned int fpga_clocking_reg;
542 unsigned int master_clock_selection;
543 unsigned long master_clock_per = 0;
544 unsigned long fb_div_selection;
545 unsigned int vco_div_reg_value;
546 unsigned long vco_div_selection;
547 unsigned long sys_per = 0;
550 /*-------------------------------------------------------------------------+
551 | Read FPGA reg 0 and reg 1 to get FPGA reg information
552 +-------------------------------------------------------------------------*/
553 fpga_clocking_reg = in16(FPGA_REG16);
556 /* Determine Master Clock Source Selection */
557 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
559 switch(master_clock_selection) {
560 case FPGA_REG16_MASTER_CLK_66_66:
561 master_clock_per = PERIOD_66_66MHZ;
563 case FPGA_REG16_MASTER_CLK_50:
564 master_clock_per = PERIOD_50_00MHZ;
566 case FPGA_REG16_MASTER_CLK_33_33:
567 master_clock_per = PERIOD_33_33MHZ;
569 case FPGA_REG16_MASTER_CLK_25:
570 master_clock_per = PERIOD_25_00MHZ;
572 case FPGA_REG16_MASTER_CLK_EXT:
573 if ((extClkVal==EXTCLK_33_33)
574 && (extClkVal==EXTCLK_50)
575 && (extClkVal==EXTCLK_66_66)
576 && (extClkVal==EXTCLK_83)) {
577 /* calculate master clock period from external clock value */
578 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
581 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
587 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
592 /* Determine FB divisors values */
593 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
594 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
595 fb_div_selection = FPGA_FB_DIV_6;
597 fb_div_selection = FPGA_FB_DIV_12;
599 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
600 fb_div_selection = FPGA_FB_DIV_10;
602 fb_div_selection = FPGA_FB_DIV_20;
605 /* Determine VCO divisors values */
606 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
608 switch(vco_div_reg_value) {
609 case FPGA_REG16_VCO_DIV_4:
610 vco_div_selection = FPGA_VCO_DIV_4;
612 case FPGA_REG16_VCO_DIV_6:
613 vco_div_selection = FPGA_VCO_DIV_6;
615 case FPGA_REG16_VCO_DIV_8:
616 vco_div_selection = FPGA_VCO_DIV_8;
618 case FPGA_REG16_VCO_DIV_10:
620 vco_div_selection = FPGA_VCO_DIV_10;
624 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
625 switch(master_clock_per) {
626 case PERIOD_25_00MHZ:
627 if (fb_div_selection == FPGA_FB_DIV_12) {
628 if (vco_div_selection == FPGA_VCO_DIV_4)
629 sys_per = PERIOD_75_00MHZ;
630 if (vco_div_selection == FPGA_VCO_DIV_6)
631 sys_per = PERIOD_50_00MHZ;
634 case PERIOD_33_33MHZ:
635 if (fb_div_selection == FPGA_FB_DIV_6) {
636 if (vco_div_selection == FPGA_VCO_DIV_4)
637 sys_per = PERIOD_50_00MHZ;
638 if (vco_div_selection == FPGA_VCO_DIV_6)
639 sys_per = PERIOD_33_33MHZ;
641 if (fb_div_selection == FPGA_FB_DIV_10) {
642 if (vco_div_selection == FPGA_VCO_DIV_4)
643 sys_per = PERIOD_83_33MHZ;
644 if (vco_div_selection == FPGA_VCO_DIV_10)
645 sys_per = PERIOD_33_33MHZ;
647 if (fb_div_selection == FPGA_FB_DIV_12) {
648 if (vco_div_selection == FPGA_VCO_DIV_4)
649 sys_per = PERIOD_100_00MHZ;
650 if (vco_div_selection == FPGA_VCO_DIV_6)
651 sys_per = PERIOD_66_66MHZ;
652 if (vco_div_selection == FPGA_VCO_DIV_8)
653 sys_per = PERIOD_50_00MHZ;
656 case PERIOD_50_00MHZ:
657 if (fb_div_selection == FPGA_FB_DIV_6) {
658 if (vco_div_selection == FPGA_VCO_DIV_4)
659 sys_per = PERIOD_75_00MHZ;
660 if (vco_div_selection == FPGA_VCO_DIV_6)
661 sys_per = PERIOD_50_00MHZ;
663 if (fb_div_selection == FPGA_FB_DIV_10) {
664 if (vco_div_selection == FPGA_VCO_DIV_6)
665 sys_per = PERIOD_83_33MHZ;
666 if (vco_div_selection == FPGA_VCO_DIV_10)
667 sys_per = PERIOD_50_00MHZ;
669 if (fb_div_selection == FPGA_FB_DIV_12) {
670 if (vco_div_selection == FPGA_VCO_DIV_6)
671 sys_per = PERIOD_100_00MHZ;
672 if (vco_div_selection == FPGA_VCO_DIV_8)
673 sys_per = PERIOD_75_00MHZ;
676 case PERIOD_66_66MHZ:
677 if (fb_div_selection == FPGA_FB_DIV_6) {
678 if (vco_div_selection == FPGA_VCO_DIV_4)
679 sys_per = PERIOD_100_00MHZ;
680 if (vco_div_selection == FPGA_VCO_DIV_6)
681 sys_per = PERIOD_66_66MHZ;
682 if (vco_div_selection == FPGA_VCO_DIV_8)
683 sys_per = PERIOD_50_00MHZ;
685 if (fb_div_selection == FPGA_FB_DIV_10) {
686 if (vco_div_selection == FPGA_VCO_DIV_8)
687 sys_per = PERIOD_83_33MHZ;
688 if (vco_div_selection == FPGA_VCO_DIV_10)
689 sys_per = PERIOD_66_66MHZ;
691 if (fb_div_selection == FPGA_FB_DIV_12) {
692 if (vco_div_selection == FPGA_VCO_DIV_8)
693 sys_per = PERIOD_100_00MHZ;
701 /* Other combinations are not supported */
702 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
706 /* calcul system clock without cheking */
707 /* if engineering option clock no check is selected */
708 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
709 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
715 /*-------------------------------------------------------------------------+
716 | determine_pci_clock_per.
717 +-------------------------------------------------------------------------*/
718 unsigned long determine_pci_clock_per(void)
720 unsigned long pci_clock_selection, pci_period;
722 /*-------------------------------------------------------------------------+
723 | Read FPGA reg 6 to get PCI 0 FPGA reg information
724 +-------------------------------------------------------------------------*/
725 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
728 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
730 switch (pci_clock_selection) {
731 case FPGA_REG16_PCI0_CLK_133_33:
732 pci_period = PERIOD_133_33MHZ;
734 case FPGA_REG16_PCI0_CLK_100:
735 pci_period = PERIOD_100_00MHZ;
737 case FPGA_REG16_PCI0_CLK_66_66:
738 pci_period = PERIOD_66_66MHZ;
741 pci_period = PERIOD_33_33MHZ;;
749 ulong get_OPB_freq (void)
753 get_sys_info (&sys_info);
754 return sys_info.freqOPB;
757 #elif defined(CONFIG_XILINX_405)
758 extern void get_sys_info (sys_info_t * sysInfo);
759 extern ulong get_PCI_freq (void);
761 #elif defined(CONFIG_AP1000)
762 void get_sys_info (sys_info_t * sysInfo)
764 sysInfo->freqProcessor = 240 * 1000 * 1000;
765 sysInfo->freqPLB = 80 * 1000 * 1000;
766 sysInfo->freqPCI = 33 * 1000 * 1000;
769 #elif defined(CONFIG_405)
771 void get_sys_info (sys_info_t * sysInfo)
773 sysInfo->freqVCOMhz=3125000;
774 sysInfo->freqProcessor=12*1000*1000;
775 sysInfo->freqPLB=50*1000*1000;
776 sysInfo->freqPCI=66*1000*1000;
779 #elif defined(CONFIG_405EP)
780 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
782 unsigned long pllmr0;
783 unsigned long pllmr1;
784 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
786 unsigned long pllmr0_ccdv;
789 * Read PLL Mode registers
791 pllmr0 = mfdcr (cpc0_pllmr0);
792 pllmr1 = mfdcr (cpc0_pllmr1);
795 * Determine forward divider A
797 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
800 * Determine forward divider B (should be equal to A)
802 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
807 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
808 if (sysInfo->pllFbkDiv == 0)
809 sysInfo->pllFbkDiv = 16;
814 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
819 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
822 * Determine EXTBUS_DIV.
824 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
829 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
832 * Determine the M factor
834 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
837 * Determine VCO clock frequency
839 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
840 (unsigned long long)sysClkPeriodPs;
843 * Determine CPU clock frequency
845 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
846 if (pllmr1 & PLLMR1_SSCS_MASK) {
848 * This is true if FWDVA == FWDVB:
849 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
852 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
853 / sysInfo->pllFwdDiv / pllmr0_ccdv;
855 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
859 * Determine PLB clock frequency
861 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
863 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
865 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
869 /********************************************
871 * return OPB bus freq in Hz
872 *********************************************/
873 ulong get_OPB_freq (void)
877 PPC4xx_SYS_INFO sys_info;
879 get_sys_info (&sys_info);
880 val = sys_info.freqPLB / sys_info.pllOpbDiv;
886 /********************************************
888 * return PCI bus freq in Hz
889 *********************************************/
890 ulong get_PCI_freq (void)
893 PPC4xx_SYS_INFO sys_info;
895 get_sys_info (&sys_info);
896 val = sys_info.freqPLB / sys_info.pllPciDiv;
900 #elif defined(CONFIG_405EZ)
901 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
903 unsigned long cpr_plld;
904 unsigned long cpr_pllc;
905 unsigned long cpr_primad;
906 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
907 unsigned long primad_cpudv;
911 * Read PLL Mode registers
913 mfcpr(cprplld, cpr_plld);
914 mfcpr(cprpllc, cpr_pllc);
917 * Determine forward divider A
919 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
922 * Determine forward divider B
924 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
925 if (sysInfo->pllFwdDivB == 0)
926 sysInfo->pllFwdDivB = 8;
931 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
932 if (sysInfo->pllFbkDiv == 0)
933 sysInfo->pllFbkDiv = 256;
936 * Read CPR_PRIMAD register
938 mfcpr(cprprimad, cpr_primad);
943 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
944 if (sysInfo->pllPlbDiv == 0)
945 sysInfo->pllPlbDiv = 16;
948 * Determine EXTBUS_DIV.
950 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
951 if (sysInfo->pllExtBusDiv == 0)
952 sysInfo->pllExtBusDiv = 16;
957 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
958 if (sysInfo->pllOpbDiv == 0)
959 sysInfo->pllOpbDiv = 16;
962 * Determine the M factor
964 if (cpr_pllc & PLLC_SRC_MASK)
965 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
967 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
970 * Determine VCO clock frequency
972 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
973 (unsigned long long)sysClkPeriodPs;
976 * Determine CPU clock frequency
978 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
979 if (primad_cpudv == 0)
982 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
983 sysInfo->pllFwdDiv / primad_cpudv;
986 * Determine PLB clock frequency
988 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
989 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
991 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
992 sysInfo->pllExtBusDiv;
994 sysInfo->freqUART = sysInfo->freqVCOHz;
997 /********************************************
999 * return OPB bus freq in Hz
1000 *********************************************/
1001 ulong get_OPB_freq (void)
1005 PPC4xx_SYS_INFO sys_info;
1007 get_sys_info (&sys_info);
1008 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1013 #elif defined(CONFIG_405EX)
1016 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1017 * We need the specs!!!!
1019 static unsigned char get_fbdv(unsigned char index)
1021 unsigned char ret = 0;
1022 /* This is table should be 256 bytes.
1023 * Only take first 52 values.
1025 unsigned char fbdv_tb[] = {
1026 0x00, 0xff, 0x7f, 0xfd,
1027 0x7a, 0xf5, 0x6a, 0xd5,
1028 0x2a, 0xd4, 0x29, 0xd3,
1029 0x26, 0xcc, 0x19, 0xb3,
1030 0x67, 0xce, 0x1d, 0xbb,
1031 0x77, 0xee, 0x5d, 0xba,
1032 0x74, 0xe9, 0x52, 0xa5,
1033 0x4b, 0x96, 0x2c, 0xd8,
1034 0x31, 0xe3, 0x46, 0x8d,
1035 0x1b, 0xb7, 0x6f, 0xde,
1036 0x3d, 0xfb, 0x76, 0xed,
1037 0x5a, 0xb5, 0x6b, 0xd6,
1038 0x2d, 0xdb, 0x36, 0xec,
1042 if ((index & 0x7f) == 0)
1044 while (ret < sizeof (fbdv_tb)) {
1045 if (fbdv_tb[ret] == index)
1054 #define PLL_FBK_PLL_LOCAL 0
1055 #define PLL_FBK_CPU 1
1056 #define PLL_FBK_PERCLK 5
1058 void get_sys_info (sys_info_t * sysInfo)
1060 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1061 unsigned long m = 1;
1063 unsigned char fwdva[16] = {
1064 1, 2, 14, 9, 4, 11, 16, 13,
1065 12, 5, 6, 15, 10, 7, 8, 3,
1067 unsigned char sel, cpudv0, plb2xDiv;
1069 mfcpr(cpr0_plld, tmp);
1072 * Determine forward divider A
1074 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1077 * Determine FBK_DIV.
1079 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1084 sysInfo->pllPlbDiv = 2;
1089 mfcpr(cpr0_perd, tmp);
1090 tmp = (tmp >> 24) & 0x03;
1091 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1096 mfcpr(cpr0_opbd, tmp);
1097 tmp = (tmp >> 24) & 0x03;
1098 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1100 /* Determine PLB2XDV0 */
1101 mfcpr(cpr0_plbd, tmp);
1102 tmp = (tmp >> 16) & 0x07;
1103 plb2xDiv = (tmp == 0) ? 8 : tmp;
1105 /* Determine CPUDV0 */
1106 mfcpr(cpr0_cpud, tmp);
1107 tmp = (tmp >> 24) & 0x07;
1108 cpudv0 = (tmp == 0) ? 8 : tmp;
1110 /* Determine SEL(5:7) in CPR0_PLLC */
1111 mfcpr(cpr0_pllc, tmp);
1112 sel = (tmp >> 24) & 0x07;
1115 * Determine the M factor
1116 * PLL local: M = FBDV
1117 * CPU clock: M = FBDV * FWDVA * CPUDV0
1118 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1123 m = sysInfo->pllFwdDiv * cpudv0;
1125 case PLL_FBK_PERCLK:
1126 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1127 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1129 case PLL_FBK_PLL_LOCAL:
1132 printf("%s unknown m\n", __FUNCTION__);
1136 m *= sysInfo->pllFbkDiv;
1139 * Determine VCO clock frequency
1141 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1142 (unsigned long long)sysClkPeriodPs;
1145 * Determine CPU clock frequency
1147 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1150 * Determine PLB clock frequency, ddr1x should be the same
1152 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1153 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1154 sysInfo->freqDDR = sysInfo->freqPLB;
1155 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1156 sysInfo->freqUART = sysInfo->freqPLB;
1159 /********************************************
1161 * return OPB bus freq in Hz
1162 *********************************************/
1163 ulong get_OPB_freq (void)
1167 PPC4xx_SYS_INFO sys_info;
1169 get_sys_info (&sys_info);
1170 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1177 int get_clocks (void)
1179 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1180 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1181 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1183 sys_info_t sys_info;
1185 get_sys_info (&sys_info);
1186 gd->cpu_clk = sys_info.freqProcessor;
1187 gd->bus_clk = sys_info.freqPLB;
1189 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1191 #ifdef CONFIG_IOP480
1192 gd->cpu_clk = 66000000;
1193 gd->bus_clk = 66000000;
1199 /********************************************
1201 * return PLB bus freq in Hz
1202 *********************************************/
1203 ulong get_bus_freq (ulong dummy)
1207 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1208 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1209 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1211 sys_info_t sys_info;
1213 get_sys_info (&sys_info);
1214 val = sys_info.freqPLB;
1216 #elif defined(CONFIG_IOP480)
1221 # error get_bus_freq() not implemented