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>
26 #include <asm/ppc4xx.h>
27 #include <asm/processor.h>
29 DECLARE_GLOBAL_DATA_PTR;
31 #define ONE_BILLION 1000000000
33 #define DEBUGF(fmt,args...) printf(fmt ,##args)
35 #define DEBUGF(fmt,args...)
38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
40 #if defined(CONFIG_405GP) || defined(CONFIG_405CR)
42 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
45 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
51 * Read PLL Mode register
53 pllmr = mfdcr (CPC0_PLLMR);
56 * Read Pin Strapping register
58 psr = mfdcr (CPC0_PSR);
63 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
68 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
69 if (sysInfo->pllFbkDiv == 0) {
70 sysInfo->pllFbkDiv = 16;
76 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
81 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
84 * Determine EXTBUS_DIV.
86 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
91 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
94 * Check if PPC405GPr used (mask minor revision field)
96 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
98 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
100 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
103 * Determine factor m depending on PLL feedback clock source
105 if (!(psr & PSR_PCI_ASYNC_EN)) {
106 if (psr & PSR_NEW_MODE_EN) {
108 * sync pci clock used as feedback (new mode)
110 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
113 * sync pci clock used as feedback (legacy mode)
115 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
117 } else if (psr & PSR_NEW_MODE_EN) {
118 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
120 * PerClk used as feedback (new mode)
122 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
125 * CPU clock used as feedback (new mode)
127 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
129 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
131 * PerClk used as feedback (legacy mode)
133 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
136 * PLB clock used as feedback (legacy mode)
138 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
141 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
142 (unsigned long long)sysClkPeriodPs;
143 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
144 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
147 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
148 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
149 * to make sure it is within the proper range.
150 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
151 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
153 if (sysInfo->pllFwdDiv == 1) {
154 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
155 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
157 sysInfo->freqVCOHz = ( 1000000000000LL *
158 (unsigned long long)sysInfo->pllFwdDiv *
159 (unsigned long long)sysInfo->pllFbkDiv *
160 (unsigned long long)sysInfo->pllPlbDiv
161 ) / (unsigned long long)sysClkPeriodPs;
162 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
163 sysInfo->pllFbkDiv)) * 10000;
164 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
168 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
169 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
170 sysInfo->freqUART = sysInfo->freqProcessor;
174 /********************************************
176 * return PCI bus freq in Hz
177 *********************************************/
178 ulong get_PCI_freq (void)
181 PPC4xx_SYS_INFO sys_info;
183 get_sys_info (&sys_info);
184 val = sys_info.freqPLB / sys_info.pllPciDiv;
189 #elif defined(CONFIG_440)
191 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
192 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
193 static u8 pll_fwdv_multi_bits[] = {
194 /* values for: 1 - 16 */
195 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
196 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
199 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
203 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
204 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
210 static u8 pll_fbdv_multi_bits[] = {
211 /* values for: 1 - 100 */
212 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
213 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
214 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
215 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
216 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
217 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
218 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
219 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
220 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
221 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
222 /* values for: 101 - 200 */
223 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
224 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
225 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
226 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
227 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
228 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
229 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
230 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
231 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
232 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
233 /* values for: 201 - 255 */
234 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
235 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
236 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
237 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
238 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
239 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
242 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
246 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
247 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
253 #if defined(CONFIG_APM821XX)
255 void get_sys_info(sys_info_t *sysInfo)
261 unsigned long plb2dv;
262 unsigned long ddr2dv;
264 /* Calculate Forward divisor A and Feeback divisor */
265 mfcpr(CPR0_PLLD, plld);
267 temp = CPR0_PLLD_FWDVA(plld);
268 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
270 temp = CPR0_PLLD_FDV(plld);
271 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
273 /* Calculate OPB clock divisor */
274 mfcpr(CPR0_OPBD, temp);
275 temp = CPR0_OPBD_OPBDV(temp);
276 sysInfo->pllOpbDiv = temp ? temp : 4;
278 /* Calculate Peripheral clock divisor */
279 mfcpr(CPR0_PERD, temp);
280 temp = CPR0_PERD_PERDV(temp);
281 sysInfo->pllExtBusDiv = temp ? temp : 4;
283 /* Calculate CPU clock divisor */
284 mfcpr(CPR0_CPUD, temp);
285 temp = CPR0_CPUD_CPUDV(temp);
286 cpudv = temp ? temp : 8;
288 /* Calculate PLB2 clock divisor */
289 mfcpr(CPR0_PLB2D, temp);
290 temp = CPR0_PLB2D_PLB2DV(temp);
291 plb2dv = temp ? temp : 4;
293 /* Calculate DDR2 clock divisor */
294 mfcpr(CPR0_DDR2D, temp);
295 temp = CPR0_DDR2D_DDR2DV(temp);
296 ddr2dv = temp ? temp : 4;
298 /* Calculate 'M' based on feedback source */
299 mfcpr(CPR0_PLLC, temp);
300 temp = CPR0_PLLC_SEL(temp);
302 /* PLL internal feedback */
303 mul = sysInfo->pllFbkDiv;
305 /* PLL PerClk feedback */
306 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
307 * plb2dv * 2 * sysInfo->pllOpbDiv *
308 sysInfo->pllExtBusDiv;
311 /* Now calculate the individual clocks */
312 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
313 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
314 sysInfo->pllFwdDivA / cpudv;
315 sysInfo->freqPLB = sysInfo->freqVCOMhz /
316 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
317 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
318 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
319 sysInfo->freqDDR = sysInfo->freqVCOMhz /
320 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
321 sysInfo->freqUART = sysInfo->freqPLB;
326 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
329 void get_sys_info (sys_info_t * sysInfo)
335 unsigned long plbedv0;
337 /* Extract configured divisors */
338 mfsdr(SDR0_SDSTP0, strp0);
339 mfsdr(SDR0_SDSTP1, strp1);
341 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
342 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
344 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
345 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
347 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
348 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
350 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
351 sysInfo->pllOpbDiv = temp ? temp : 4;
353 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
354 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
355 sysInfo->pllExtBusDiv = temp ? temp : 4;
357 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
358 plbedv0 = temp ? temp: 8;
360 /* Calculate 'M' based on feedback source */
361 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
363 /* PLL internal feedback */
364 m = sysInfo->pllFbkDiv;
366 /* PLL PerClk feedback */
367 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
368 sysInfo->pllExtBusDiv;
371 /* Now calculate the individual clocks */
372 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
373 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
374 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
375 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
376 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
377 sysInfo->freqDDR = sysInfo->freqPLB;
378 sysInfo->freqUART = sysInfo->freqPLB;
384 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
385 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
386 void get_sys_info (sys_info_t *sysInfo)
392 unsigned long prbdv0;
394 WARNING: ASSUMES the following:
400 /* Decode CPR0_PLLD0 for divisors */
401 mfcpr(CPR0_PLLD, reg);
402 temp = (reg & PLLD_FWDVA_MASK) >> 16;
403 sysInfo->pllFwdDivA = temp ? temp : 16;
404 temp = (reg & PLLD_FWDVB_MASK) >> 8;
405 sysInfo->pllFwdDivB = temp ? temp: 8 ;
406 temp = (reg & PLLD_FBDV_MASK) >> 24;
407 sysInfo->pllFbkDiv = temp ? temp : 32;
408 lfdiv = reg & PLLD_LFBDV_MASK;
410 mfcpr(CPR0_OPBD0, reg);
411 temp = (reg & OPBDDV_MASK) >> 24;
412 sysInfo->pllOpbDiv = temp ? temp : 4;
414 mfcpr(CPR0_PERD, reg);
415 temp = (reg & PERDV_MASK) >> 24;
416 sysInfo->pllExtBusDiv = temp ? temp : 8;
418 mfcpr(CPR0_PRIMBD0, reg);
419 temp = (reg & PRBDV_MASK) >> 24;
420 prbdv0 = temp ? temp : 8;
422 mfcpr(CPR0_SPCID, reg);
423 temp = (reg & SPCID_MASK) >> 24;
424 sysInfo->pllPciDiv = temp ? temp : 4;
426 /* Calculate 'M' based on feedback source */
427 mfsdr(SDR0_SDSTP0, reg);
428 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
429 if (temp == 0) { /* PLL output */
430 /* Figure which pll to use */
431 mfcpr(CPR0_PLLC, reg);
432 temp = (reg & PLLC_SRC_MASK) >> 29;
433 if (!temp) /* PLLOUTA */
434 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
436 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
438 else if (temp == 1) /* CPU output */
439 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
441 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
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/prbdv0;
447 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
448 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
449 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
450 sysInfo->freqUART = sysInfo->freqPLB;
452 /* Figure which timer source to use */
453 if (mfspr(SPRN_CCR1) & 0x0080) {
454 /* External Clock, assume same as SYS_CLK */
455 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
456 if (CONFIG_SYS_CLK_FREQ > temp)
457 sysInfo->freqTmrClk = temp;
459 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
461 else /* Internal clock */
462 sysInfo->freqTmrClk = sysInfo->freqProcessor;
465 /********************************************
467 * return PCI bus freq in Hz
468 *********************************************/
469 ulong get_PCI_freq (void)
472 get_sys_info (&sys_info);
473 return sys_info.freqPCI;
476 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
477 && !defined(CONFIG_XILINX_440)
478 void get_sys_info (sys_info_t * sysInfo)
484 /* Extract configured divisors */
485 strp0 = mfdcr( CPC0_STRP0 );
486 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
487 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
488 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
489 sysInfo->pllFbkDiv = temp ? temp : 16;
490 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
491 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
493 /* Calculate 'M' based on feedback source */
494 if( strp0 & PLLSYS0_EXTSL_MASK )
495 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
497 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
499 /* Now calculate the individual clocks */
500 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
501 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
502 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
503 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
504 sysInfo->freqPLB >>= 1;
505 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
506 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
507 sysInfo->freqUART = sysInfo->freqPLB;
511 #if !defined(CONFIG_XILINX_440)
512 void get_sys_info (sys_info_t * sysInfo)
520 unsigned long prbdv0;
522 #if defined(CONFIG_YUCCA)
523 unsigned long sys_freq;
524 unsigned long sys_per=0;
526 unsigned long pci_clock_per;
527 unsigned long sdr_ddrpll;
529 /*-------------------------------------------------------------------------+
530 | Get the system clock period.
531 +-------------------------------------------------------------------------*/
532 sys_per = determine_sysper();
534 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
536 /*-------------------------------------------------------------------------+
537 | Calculate the system clock speed from the period.
538 +-------------------------------------------------------------------------*/
539 sys_freq = (ONE_BILLION / sys_per) * 1000;
542 /* Extract configured divisors */
543 mfsdr( SDR0_SDSTP0,strp0 );
544 mfsdr( SDR0_SDSTP1,strp1 );
546 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
547 sysInfo->pllFwdDivA = temp ? temp : 16 ;
548 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
549 sysInfo->pllFwdDivB = temp ? temp: 8 ;
550 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
551 sysInfo->pllFbkDiv = temp ? temp : 32;
552 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
553 sysInfo->pllOpbDiv = temp ? temp : 4;
554 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
555 sysInfo->pllExtBusDiv = temp ? temp : 4;
556 prbdv0 = (strp0 >> 2) & 0x7;
558 /* Calculate 'M' based on feedback source */
559 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
560 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
561 lfdiv = temp1 ? temp1 : 64;
562 if (temp == 0) { /* PLL output */
563 /* Figure which pll to use */
564 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
566 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
568 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
570 else if (temp == 1) /* CPU output */
571 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
573 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
575 /* Now calculate the individual clocks */
576 #if defined(CONFIG_YUCCA)
577 sysInfo->freqVCOMhz = (m * sys_freq) ;
579 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
581 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
582 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
583 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
584 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
586 #if defined(CONFIG_YUCCA)
587 /* Determine PCI Clock Period */
588 pci_clock_per = determine_pci_clock_per();
589 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
590 mfsdr(SDR0_DDR0, sdr_ddrpll);
591 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
594 sysInfo->freqUART = sysInfo->freqPLB;
598 #endif /* CONFIG_XILINX_440 */
600 #if defined(CONFIG_YUCCA)
601 unsigned long determine_sysper(void)
603 unsigned int fpga_clocking_reg;
604 unsigned int master_clock_selection;
605 unsigned long master_clock_per = 0;
606 unsigned long fb_div_selection;
607 unsigned int vco_div_reg_value;
608 unsigned long vco_div_selection;
609 unsigned long sys_per = 0;
612 /*-------------------------------------------------------------------------+
613 | Read FPGA reg 0 and reg 1 to get FPGA reg information
614 +-------------------------------------------------------------------------*/
615 fpga_clocking_reg = in16(FPGA_REG16);
618 /* Determine Master Clock Source Selection */
619 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
621 switch(master_clock_selection) {
622 case FPGA_REG16_MASTER_CLK_66_66:
623 master_clock_per = PERIOD_66_66MHZ;
625 case FPGA_REG16_MASTER_CLK_50:
626 master_clock_per = PERIOD_50_00MHZ;
628 case FPGA_REG16_MASTER_CLK_33_33:
629 master_clock_per = PERIOD_33_33MHZ;
631 case FPGA_REG16_MASTER_CLK_25:
632 master_clock_per = PERIOD_25_00MHZ;
634 case FPGA_REG16_MASTER_CLK_EXT:
635 if ((extClkVal==EXTCLK_33_33)
636 && (extClkVal==EXTCLK_50)
637 && (extClkVal==EXTCLK_66_66)
638 && (extClkVal==EXTCLK_83)) {
639 /* calculate master clock period from external clock value */
640 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
643 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
649 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
654 /* Determine FB divisors values */
655 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
656 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
657 fb_div_selection = FPGA_FB_DIV_6;
659 fb_div_selection = FPGA_FB_DIV_12;
661 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
662 fb_div_selection = FPGA_FB_DIV_10;
664 fb_div_selection = FPGA_FB_DIV_20;
667 /* Determine VCO divisors values */
668 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
670 switch(vco_div_reg_value) {
671 case FPGA_REG16_VCO_DIV_4:
672 vco_div_selection = FPGA_VCO_DIV_4;
674 case FPGA_REG16_VCO_DIV_6:
675 vco_div_selection = FPGA_VCO_DIV_6;
677 case FPGA_REG16_VCO_DIV_8:
678 vco_div_selection = FPGA_VCO_DIV_8;
680 case FPGA_REG16_VCO_DIV_10:
682 vco_div_selection = FPGA_VCO_DIV_10;
686 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
687 switch(master_clock_per) {
688 case PERIOD_25_00MHZ:
689 if (fb_div_selection == FPGA_FB_DIV_12) {
690 if (vco_div_selection == FPGA_VCO_DIV_4)
691 sys_per = PERIOD_75_00MHZ;
692 if (vco_div_selection == FPGA_VCO_DIV_6)
693 sys_per = PERIOD_50_00MHZ;
696 case PERIOD_33_33MHZ:
697 if (fb_div_selection == FPGA_FB_DIV_6) {
698 if (vco_div_selection == FPGA_VCO_DIV_4)
699 sys_per = PERIOD_50_00MHZ;
700 if (vco_div_selection == FPGA_VCO_DIV_6)
701 sys_per = PERIOD_33_33MHZ;
703 if (fb_div_selection == FPGA_FB_DIV_10) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_83_33MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_10)
707 sys_per = PERIOD_33_33MHZ;
709 if (fb_div_selection == FPGA_FB_DIV_12) {
710 if (vco_div_selection == FPGA_VCO_DIV_4)
711 sys_per = PERIOD_100_00MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_6)
713 sys_per = PERIOD_66_66MHZ;
714 if (vco_div_selection == FPGA_VCO_DIV_8)
715 sys_per = PERIOD_50_00MHZ;
718 case PERIOD_50_00MHZ:
719 if (fb_div_selection == FPGA_FB_DIV_6) {
720 if (vco_div_selection == FPGA_VCO_DIV_4)
721 sys_per = PERIOD_75_00MHZ;
722 if (vco_div_selection == FPGA_VCO_DIV_6)
723 sys_per = PERIOD_50_00MHZ;
725 if (fb_div_selection == FPGA_FB_DIV_10) {
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_83_33MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_10)
729 sys_per = PERIOD_50_00MHZ;
731 if (fb_div_selection == FPGA_FB_DIV_12) {
732 if (vco_div_selection == FPGA_VCO_DIV_6)
733 sys_per = PERIOD_100_00MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_8)
735 sys_per = PERIOD_75_00MHZ;
738 case PERIOD_66_66MHZ:
739 if (fb_div_selection == FPGA_FB_DIV_6) {
740 if (vco_div_selection == FPGA_VCO_DIV_4)
741 sys_per = PERIOD_100_00MHZ;
742 if (vco_div_selection == FPGA_VCO_DIV_6)
743 sys_per = PERIOD_66_66MHZ;
744 if (vco_div_selection == FPGA_VCO_DIV_8)
745 sys_per = PERIOD_50_00MHZ;
747 if (fb_div_selection == FPGA_FB_DIV_10) {
748 if (vco_div_selection == FPGA_VCO_DIV_8)
749 sys_per = PERIOD_83_33MHZ;
750 if (vco_div_selection == FPGA_VCO_DIV_10)
751 sys_per = PERIOD_66_66MHZ;
753 if (fb_div_selection == FPGA_FB_DIV_12) {
754 if (vco_div_selection == FPGA_VCO_DIV_8)
755 sys_per = PERIOD_100_00MHZ;
763 /* Other combinations are not supported */
764 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
768 /* calcul system clock without cheking */
769 /* if engineering option clock no check is selected */
770 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
771 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
777 /*-------------------------------------------------------------------------+
778 | determine_pci_clock_per.
779 +-------------------------------------------------------------------------*/
780 unsigned long determine_pci_clock_per(void)
782 unsigned long pci_clock_selection, pci_period;
784 /*-------------------------------------------------------------------------+
785 | Read FPGA reg 6 to get PCI 0 FPGA reg information
786 +-------------------------------------------------------------------------*/
787 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
790 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
792 switch (pci_clock_selection) {
793 case FPGA_REG16_PCI0_CLK_133_33:
794 pci_period = PERIOD_133_33MHZ;
796 case FPGA_REG16_PCI0_CLK_100:
797 pci_period = PERIOD_100_00MHZ;
799 case FPGA_REG16_PCI0_CLK_66_66:
800 pci_period = PERIOD_66_66MHZ;
803 pci_period = PERIOD_33_33MHZ;;
811 #elif defined(CONFIG_XILINX_405)
812 extern void get_sys_info (sys_info_t * sysInfo);
813 extern ulong get_PCI_freq (void);
815 #elif defined(CONFIG_AP1000)
816 void get_sys_info (sys_info_t * sysInfo)
818 sysInfo->freqProcessor = 240 * 1000 * 1000;
819 sysInfo->freqPLB = 80 * 1000 * 1000;
820 sysInfo->freqPCI = 33 * 1000 * 1000;
823 #elif defined(CONFIG_405)
825 void get_sys_info (sys_info_t * sysInfo)
827 sysInfo->freqVCOMhz=3125000;
828 sysInfo->freqProcessor=12*1000*1000;
829 sysInfo->freqPLB=50*1000*1000;
830 sysInfo->freqPCI=66*1000*1000;
833 #elif defined(CONFIG_405EP)
834 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
836 unsigned long pllmr0;
837 unsigned long pllmr1;
838 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
840 unsigned long pllmr0_ccdv;
843 * Read PLL Mode registers
845 pllmr0 = mfdcr (CPC0_PLLMR0);
846 pllmr1 = mfdcr (CPC0_PLLMR1);
849 * Determine forward divider A
851 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
854 * Determine forward divider B (should be equal to A)
856 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
861 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
862 if (sysInfo->pllFbkDiv == 0)
863 sysInfo->pllFbkDiv = 16;
868 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
873 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
876 * Determine EXTBUS_DIV.
878 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
883 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
886 * Determine the M factor
888 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
891 * Determine VCO clock frequency
893 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
894 (unsigned long long)sysClkPeriodPs;
897 * Determine CPU clock frequency
899 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
900 if (pllmr1 & PLLMR1_SSCS_MASK) {
902 * This is true if FWDVA == FWDVB:
903 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
906 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
907 / sysInfo->pllFwdDiv / pllmr0_ccdv;
909 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
913 * Determine PLB clock frequency
915 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
917 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
919 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
921 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
925 /********************************************
927 * return PCI bus freq in Hz
928 *********************************************/
929 ulong get_PCI_freq (void)
932 PPC4xx_SYS_INFO sys_info;
934 get_sys_info (&sys_info);
935 val = sys_info.freqPLB / sys_info.pllPciDiv;
939 #elif defined(CONFIG_405EZ)
940 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
942 unsigned long cpr_plld;
943 unsigned long cpr_pllc;
944 unsigned long cpr_primad;
945 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
946 unsigned long primad_cpudv;
948 unsigned long plloutb;
951 * Read PLL Mode registers
953 mfcpr(CPR0_PLLD, cpr_plld);
954 mfcpr(CPR0_PLLC, cpr_pllc);
957 * Determine forward divider A
959 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
962 * Determine forward divider B
964 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
965 if (sysInfo->pllFwdDivB == 0)
966 sysInfo->pllFwdDivB = 8;
971 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
972 if (sysInfo->pllFbkDiv == 0)
973 sysInfo->pllFbkDiv = 256;
976 * Read CPR_PRIMAD register
978 mfcpr(CPR0_PRIMAD, cpr_primad);
983 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
984 if (sysInfo->pllPlbDiv == 0)
985 sysInfo->pllPlbDiv = 16;
988 * Determine EXTBUS_DIV.
990 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
991 if (sysInfo->pllExtBusDiv == 0)
992 sysInfo->pllExtBusDiv = 16;
997 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
998 if (sysInfo->pllOpbDiv == 0)
999 sysInfo->pllOpbDiv = 16;
1002 * Determine the M factor
1004 if (cpr_pllc & PLLC_SRC_MASK)
1005 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
1007 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
1010 * Determine VCO clock frequency
1012 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1013 (unsigned long long)sysClkPeriodPs;
1016 * Determine CPU clock frequency
1018 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
1019 if (primad_cpudv == 0)
1022 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1023 sysInfo->pllFwdDiv / primad_cpudv;
1026 * Determine PLB clock frequency
1028 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1029 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1031 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1034 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1035 sysInfo->pllExtBusDiv;
1037 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1038 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1039 sysInfo->pllFwdDivB);
1040 sysInfo->freqUART = plloutb;
1043 #elif defined(CONFIG_405EX)
1046 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1047 * We need the specs!!!!
1049 static unsigned char get_fbdv(unsigned char index)
1051 unsigned char ret = 0;
1052 /* This is table should be 256 bytes.
1053 * Only take first 52 values.
1055 unsigned char fbdv_tb[] = {
1056 0x00, 0xff, 0x7f, 0xfd,
1057 0x7a, 0xf5, 0x6a, 0xd5,
1058 0x2a, 0xd4, 0x29, 0xd3,
1059 0x26, 0xcc, 0x19, 0xb3,
1060 0x67, 0xce, 0x1d, 0xbb,
1061 0x77, 0xee, 0x5d, 0xba,
1062 0x74, 0xe9, 0x52, 0xa5,
1063 0x4b, 0x96, 0x2c, 0xd8,
1064 0x31, 0xe3, 0x46, 0x8d,
1065 0x1b, 0xb7, 0x6f, 0xde,
1066 0x3d, 0xfb, 0x76, 0xed,
1067 0x5a, 0xb5, 0x6b, 0xd6,
1068 0x2d, 0xdb, 0x36, 0xec,
1072 if ((index & 0x7f) == 0)
1074 while (ret < sizeof (fbdv_tb)) {
1075 if (fbdv_tb[ret] == index)
1084 #define PLL_FBK_PLL_LOCAL 0
1085 #define PLL_FBK_CPU 1
1086 #define PLL_FBK_PERCLK 5
1088 void get_sys_info (sys_info_t * sysInfo)
1090 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1091 unsigned long m = 1;
1093 unsigned char fwdva[16] = {
1094 1, 2, 14, 9, 4, 11, 16, 13,
1095 12, 5, 6, 15, 10, 7, 8, 3,
1097 unsigned char sel, cpudv0, plb2xDiv;
1099 mfcpr(CPR0_PLLD, tmp);
1102 * Determine forward divider A
1104 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1107 * Determine FBK_DIV.
1109 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1114 sysInfo->pllPlbDiv = 2;
1119 mfcpr(CPR0_PERD, tmp);
1120 tmp = (tmp >> 24) & 0x03;
1121 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1126 mfcpr(CPR0_OPBD0, tmp);
1127 tmp = (tmp >> 24) & 0x03;
1128 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1130 /* Determine PLB2XDV0 */
1131 mfcpr(CPR0_PLBD, tmp);
1132 tmp = (tmp >> 16) & 0x07;
1133 plb2xDiv = (tmp == 0) ? 8 : tmp;
1135 /* Determine CPUDV0 */
1136 mfcpr(CPR0_CPUD, tmp);
1137 tmp = (tmp >> 24) & 0x07;
1138 cpudv0 = (tmp == 0) ? 8 : tmp;
1140 /* Determine SEL(5:7) in CPR0_PLLC */
1141 mfcpr(CPR0_PLLC, tmp);
1142 sel = (tmp >> 24) & 0x07;
1145 * Determine the M factor
1146 * PLL local: M = FBDV
1147 * CPU clock: M = FBDV * FWDVA * CPUDV0
1148 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1153 m = sysInfo->pllFwdDiv * cpudv0;
1155 case PLL_FBK_PERCLK:
1156 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1157 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1159 case PLL_FBK_PLL_LOCAL:
1162 printf("%s unknown m\n", __FUNCTION__);
1166 m *= sysInfo->pllFbkDiv;
1169 * Determine VCO clock frequency
1171 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1172 (unsigned long long)sysClkPeriodPs;
1175 * Determine CPU clock frequency
1177 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1180 * Determine PLB clock frequency, ddr1x should be the same
1182 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1183 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1184 sysInfo->freqDDR = sysInfo->freqPLB;
1185 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1186 sysInfo->freqUART = sysInfo->freqPLB;
1191 int get_clocks (void)
1193 sys_info_t sys_info;
1195 get_sys_info (&sys_info);
1196 gd->cpu_clk = sys_info.freqProcessor;
1197 gd->bus_clk = sys_info.freqPLB;
1203 /********************************************
1205 * return PLB bus freq in Hz
1206 *********************************************/
1207 ulong get_bus_freq (ulong dummy)
1211 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1212 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1213 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1215 sys_info_t sys_info;
1217 get_sys_info (&sys_info);
1218 val = sys_info.freqPLB;
1220 # error get_bus_freq() not implemented
1226 ulong get_OPB_freq (void)
1228 PPC4xx_SYS_INFO sys_info;
1230 get_sys_info (&sys_info);
1232 return sys_info.freqOPB;