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_405)
817 void get_sys_info (sys_info_t * sysInfo)
819 sysInfo->freqVCOMhz=3125000;
820 sysInfo->freqProcessor=12*1000*1000;
821 sysInfo->freqPLB=50*1000*1000;
822 sysInfo->freqPCI=66*1000*1000;
825 #elif defined(CONFIG_405EP)
826 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
828 unsigned long pllmr0;
829 unsigned long pllmr1;
830 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
832 unsigned long pllmr0_ccdv;
835 * Read PLL Mode registers
837 pllmr0 = mfdcr (CPC0_PLLMR0);
838 pllmr1 = mfdcr (CPC0_PLLMR1);
841 * Determine forward divider A
843 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
846 * Determine forward divider B (should be equal to A)
848 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
853 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
854 if (sysInfo->pllFbkDiv == 0)
855 sysInfo->pllFbkDiv = 16;
860 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
865 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
868 * Determine EXTBUS_DIV.
870 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
875 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
878 * Determine the M factor
880 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
883 * Determine VCO clock frequency
885 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
886 (unsigned long long)sysClkPeriodPs;
889 * Determine CPU clock frequency
891 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
892 if (pllmr1 & PLLMR1_SSCS_MASK) {
894 * This is true if FWDVA == FWDVB:
895 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
898 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
899 / sysInfo->pllFwdDiv / pllmr0_ccdv;
901 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
905 * Determine PLB clock frequency
907 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
909 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
911 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
913 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
917 /********************************************
919 * return PCI bus freq in Hz
920 *********************************************/
921 ulong get_PCI_freq (void)
924 PPC4xx_SYS_INFO sys_info;
926 get_sys_info (&sys_info);
927 val = sys_info.freqPLB / sys_info.pllPciDiv;
931 #elif defined(CONFIG_405EZ)
932 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
934 unsigned long cpr_plld;
935 unsigned long cpr_pllc;
936 unsigned long cpr_primad;
937 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
938 unsigned long primad_cpudv;
940 unsigned long plloutb;
943 * Read PLL Mode registers
945 mfcpr(CPR0_PLLD, cpr_plld);
946 mfcpr(CPR0_PLLC, cpr_pllc);
949 * Determine forward divider A
951 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
954 * Determine forward divider B
956 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
957 if (sysInfo->pllFwdDivB == 0)
958 sysInfo->pllFwdDivB = 8;
963 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
964 if (sysInfo->pllFbkDiv == 0)
965 sysInfo->pllFbkDiv = 256;
968 * Read CPR_PRIMAD register
970 mfcpr(CPR0_PRIMAD, cpr_primad);
975 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
976 if (sysInfo->pllPlbDiv == 0)
977 sysInfo->pllPlbDiv = 16;
980 * Determine EXTBUS_DIV.
982 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
983 if (sysInfo->pllExtBusDiv == 0)
984 sysInfo->pllExtBusDiv = 16;
989 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
990 if (sysInfo->pllOpbDiv == 0)
991 sysInfo->pllOpbDiv = 16;
994 * Determine the M factor
996 if (cpr_pllc & PLLC_SRC_MASK)
997 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
999 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
1002 * Determine VCO clock frequency
1004 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1005 (unsigned long long)sysClkPeriodPs;
1008 * Determine CPU clock frequency
1010 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
1011 if (primad_cpudv == 0)
1014 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1015 sysInfo->pllFwdDiv / primad_cpudv;
1018 * Determine PLB clock frequency
1020 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1021 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1023 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1026 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1027 sysInfo->pllExtBusDiv;
1029 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1030 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1031 sysInfo->pllFwdDivB);
1032 sysInfo->freqUART = plloutb;
1035 #elif defined(CONFIG_405EX)
1038 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1039 * We need the specs!!!!
1041 static unsigned char get_fbdv(unsigned char index)
1043 unsigned char ret = 0;
1044 /* This is table should be 256 bytes.
1045 * Only take first 52 values.
1047 unsigned char fbdv_tb[] = {
1048 0x00, 0xff, 0x7f, 0xfd,
1049 0x7a, 0xf5, 0x6a, 0xd5,
1050 0x2a, 0xd4, 0x29, 0xd3,
1051 0x26, 0xcc, 0x19, 0xb3,
1052 0x67, 0xce, 0x1d, 0xbb,
1053 0x77, 0xee, 0x5d, 0xba,
1054 0x74, 0xe9, 0x52, 0xa5,
1055 0x4b, 0x96, 0x2c, 0xd8,
1056 0x31, 0xe3, 0x46, 0x8d,
1057 0x1b, 0xb7, 0x6f, 0xde,
1058 0x3d, 0xfb, 0x76, 0xed,
1059 0x5a, 0xb5, 0x6b, 0xd6,
1060 0x2d, 0xdb, 0x36, 0xec,
1064 if ((index & 0x7f) == 0)
1066 while (ret < sizeof (fbdv_tb)) {
1067 if (fbdv_tb[ret] == index)
1076 #define PLL_FBK_PLL_LOCAL 0
1077 #define PLL_FBK_CPU 1
1078 #define PLL_FBK_PERCLK 5
1080 void get_sys_info (sys_info_t * sysInfo)
1082 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1083 unsigned long m = 1;
1085 unsigned char fwdva[16] = {
1086 1, 2, 14, 9, 4, 11, 16, 13,
1087 12, 5, 6, 15, 10, 7, 8, 3,
1089 unsigned char sel, cpudv0, plb2xDiv;
1091 mfcpr(CPR0_PLLD, tmp);
1094 * Determine forward divider A
1096 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1099 * Determine FBK_DIV.
1101 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1106 sysInfo->pllPlbDiv = 2;
1111 mfcpr(CPR0_PERD, tmp);
1112 tmp = (tmp >> 24) & 0x03;
1113 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1118 mfcpr(CPR0_OPBD0, tmp);
1119 tmp = (tmp >> 24) & 0x03;
1120 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1122 /* Determine PLB2XDV0 */
1123 mfcpr(CPR0_PLBD, tmp);
1124 tmp = (tmp >> 16) & 0x07;
1125 plb2xDiv = (tmp == 0) ? 8 : tmp;
1127 /* Determine CPUDV0 */
1128 mfcpr(CPR0_CPUD, tmp);
1129 tmp = (tmp >> 24) & 0x07;
1130 cpudv0 = (tmp == 0) ? 8 : tmp;
1132 /* Determine SEL(5:7) in CPR0_PLLC */
1133 mfcpr(CPR0_PLLC, tmp);
1134 sel = (tmp >> 24) & 0x07;
1137 * Determine the M factor
1138 * PLL local: M = FBDV
1139 * CPU clock: M = FBDV * FWDVA * CPUDV0
1140 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1145 m = sysInfo->pllFwdDiv * cpudv0;
1147 case PLL_FBK_PERCLK:
1148 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1149 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1151 case PLL_FBK_PLL_LOCAL:
1154 printf("%s unknown m\n", __FUNCTION__);
1158 m *= sysInfo->pllFbkDiv;
1161 * Determine VCO clock frequency
1163 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1164 (unsigned long long)sysClkPeriodPs;
1167 * Determine CPU clock frequency
1169 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1172 * Determine PLB clock frequency, ddr1x should be the same
1174 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1175 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1176 sysInfo->freqDDR = sysInfo->freqPLB;
1177 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1178 sysInfo->freqUART = sysInfo->freqPLB;
1183 int get_clocks (void)
1185 sys_info_t sys_info;
1187 get_sys_info (&sys_info);
1188 gd->cpu_clk = sys_info.freqProcessor;
1189 gd->bus_clk = sys_info.freqPLB;
1195 /********************************************
1197 * return PLB bus freq in Hz
1198 *********************************************/
1199 ulong get_bus_freq (ulong dummy)
1203 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1204 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1205 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1207 sys_info_t sys_info;
1209 get_sys_info (&sys_info);
1210 val = sys_info.freqPLB;
1212 # error get_bus_freq() not implemented
1218 ulong get_OPB_freq (void)
1220 PPC4xx_SYS_INFO sys_info;
1222 get_sys_info (&sys_info);
1224 return sys_info.freqOPB;