2 * (C) Copyright 2000-2008
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * SPDX-License-Identifier: GPL-2.0+
9 #include <ppc_asm.tmpl>
10 #include <asm/ppc4xx.h>
11 #include <asm/processor.h>
13 DECLARE_GLOBAL_DATA_PTR;
15 #define ONE_BILLION 1000000000
17 #define DEBUGF(fmt,args...) printf(fmt ,##args)
19 #define DEBUGF(fmt,args...)
22 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
24 #if defined(CONFIG_405GP)
26 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
29 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
35 * Read PLL Mode register
37 pllmr = mfdcr (CPC0_PLLMR);
40 * Read Pin Strapping register
42 psr = mfdcr (CPC0_PSR);
47 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
52 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
53 if (sysInfo->pllFbkDiv == 0) {
54 sysInfo->pllFbkDiv = 16;
60 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
65 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
68 * Determine EXTBUS_DIV.
70 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
75 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
78 * Check if PPC405GPr used (mask minor revision field)
80 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
82 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
84 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
87 * Determine factor m depending on PLL feedback clock source
89 if (!(psr & PSR_PCI_ASYNC_EN)) {
90 if (psr & PSR_NEW_MODE_EN) {
92 * sync pci clock used as feedback (new mode)
94 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
97 * sync pci clock used as feedback (legacy mode)
99 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
101 } else if (psr & PSR_NEW_MODE_EN) {
102 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
104 * PerClk used as feedback (new mode)
106 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
109 * CPU clock used as feedback (new mode)
111 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
113 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
115 * PerClk used as feedback (legacy mode)
117 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
120 * PLB clock used as feedback (legacy mode)
122 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
125 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
126 (unsigned long long)sysClkPeriodPs;
127 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
128 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
131 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
132 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
133 * to make sure it is within the proper range.
134 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
135 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
137 if (sysInfo->pllFwdDiv == 1) {
138 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
139 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
141 sysInfo->freqVCOHz = ( 1000000000000LL *
142 (unsigned long long)sysInfo->pllFwdDiv *
143 (unsigned long long)sysInfo->pllFbkDiv *
144 (unsigned long long)sysInfo->pllPlbDiv
145 ) / (unsigned long long)sysClkPeriodPs;
146 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
147 sysInfo->pllFbkDiv)) * 10000;
148 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
152 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
153 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
154 sysInfo->freqUART = sysInfo->freqProcessor;
158 /********************************************
160 * return PCI bus freq in Hz
161 *********************************************/
162 ulong get_PCI_freq (void)
165 PPC4xx_SYS_INFO sys_info;
167 get_sys_info (&sys_info);
168 val = sys_info.freqPLB / sys_info.pllPciDiv;
173 #elif defined(CONFIG_440)
175 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
176 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
177 static u8 pll_fwdv_multi_bits[] = {
178 /* values for: 1 - 16 */
179 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
180 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
183 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
187 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
188 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
194 static u8 pll_fbdv_multi_bits[] = {
195 /* values for: 1 - 100 */
196 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
197 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
198 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
199 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
200 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
201 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
202 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
203 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
204 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
205 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
206 /* values for: 101 - 200 */
207 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
208 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
209 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
210 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
211 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
212 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
213 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
214 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
215 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
216 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
217 /* values for: 201 - 255 */
218 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
219 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
220 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
221 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
222 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
223 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
226 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
230 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
231 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
237 #if defined(CONFIG_APM821XX)
239 void get_sys_info(sys_info_t *sysInfo)
245 unsigned long plb2dv;
246 unsigned long ddr2dv;
248 /* Calculate Forward divisor A and Feeback divisor */
249 mfcpr(CPR0_PLLD, plld);
251 temp = CPR0_PLLD_FWDVA(plld);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
254 temp = CPR0_PLLD_FDV(plld);
255 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
257 /* Calculate OPB clock divisor */
258 mfcpr(CPR0_OPBD, temp);
259 temp = CPR0_OPBD_OPBDV(temp);
260 sysInfo->pllOpbDiv = temp ? temp : 4;
262 /* Calculate Peripheral clock divisor */
263 mfcpr(CPR0_PERD, temp);
264 temp = CPR0_PERD_PERDV(temp);
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
267 /* Calculate CPU clock divisor */
268 mfcpr(CPR0_CPUD, temp);
269 temp = CPR0_CPUD_CPUDV(temp);
270 cpudv = temp ? temp : 8;
272 /* Calculate PLB2 clock divisor */
273 mfcpr(CPR0_PLB2D, temp);
274 temp = CPR0_PLB2D_PLB2DV(temp);
275 plb2dv = temp ? temp : 4;
277 /* Calculate DDR2 clock divisor */
278 mfcpr(CPR0_DDR2D, temp);
279 temp = CPR0_DDR2D_DDR2DV(temp);
280 ddr2dv = temp ? temp : 4;
282 /* Calculate 'M' based on feedback source */
283 mfcpr(CPR0_PLLC, temp);
284 temp = CPR0_PLLC_SEL(temp);
286 /* PLL internal feedback */
287 mul = sysInfo->pllFbkDiv;
289 /* PLL PerClk feedback */
290 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
291 * plb2dv * 2 * sysInfo->pllOpbDiv *
292 sysInfo->pllExtBusDiv;
295 /* Now calculate the individual clocks */
296 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
297 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
298 sysInfo->pllFwdDivA / cpudv;
299 sysInfo->freqPLB = sysInfo->freqVCOMhz /
300 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
301 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
302 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
303 sysInfo->freqDDR = sysInfo->freqVCOMhz /
304 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
305 sysInfo->freqUART = sysInfo->freqPLB;
310 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
313 void get_sys_info (sys_info_t * sysInfo)
319 unsigned long plbedv0;
321 /* Extract configured divisors */
322 mfsdr(SDR0_SDSTP0, strp0);
323 mfsdr(SDR0_SDSTP1, strp1);
325 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
326 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
328 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
329 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
331 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
332 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
334 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
335 sysInfo->pllOpbDiv = temp ? temp : 4;
337 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
338 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
339 sysInfo->pllExtBusDiv = temp ? temp : 4;
341 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
342 plbedv0 = temp ? temp: 8;
344 /* Calculate 'M' based on feedback source */
345 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
347 /* PLL internal feedback */
348 m = sysInfo->pllFbkDiv;
350 /* PLL PerClk feedback */
351 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
352 sysInfo->pllExtBusDiv;
355 /* Now calculate the individual clocks */
356 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
357 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
358 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
359 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
360 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
361 sysInfo->freqDDR = sysInfo->freqPLB;
362 sysInfo->freqUART = sysInfo->freqPLB;
368 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
369 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
370 void get_sys_info (sys_info_t *sysInfo)
376 unsigned long prbdv0;
378 WARNING: ASSUMES the following:
384 /* Decode CPR0_PLLD0 for divisors */
385 mfcpr(CPR0_PLLD, reg);
386 temp = (reg & PLLD_FWDVA_MASK) >> 16;
387 sysInfo->pllFwdDivA = temp ? temp : 16;
388 temp = (reg & PLLD_FWDVB_MASK) >> 8;
389 sysInfo->pllFwdDivB = temp ? temp: 8 ;
390 temp = (reg & PLLD_FBDV_MASK) >> 24;
391 sysInfo->pllFbkDiv = temp ? temp : 32;
392 lfdiv = reg & PLLD_LFBDV_MASK;
394 mfcpr(CPR0_OPBD0, reg);
395 temp = (reg & OPBDDV_MASK) >> 24;
396 sysInfo->pllOpbDiv = temp ? temp : 4;
398 mfcpr(CPR0_PERD, reg);
399 temp = (reg & PERDV_MASK) >> 24;
400 sysInfo->pllExtBusDiv = temp ? temp : 8;
402 mfcpr(CPR0_PRIMBD0, reg);
403 temp = (reg & PRBDV_MASK) >> 24;
404 prbdv0 = temp ? temp : 8;
406 mfcpr(CPR0_SPCID, reg);
407 temp = (reg & SPCID_MASK) >> 24;
408 sysInfo->pllPciDiv = temp ? temp : 4;
410 /* Calculate 'M' based on feedback source */
411 mfsdr(SDR0_SDSTP0, reg);
412 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
413 if (temp == 0) { /* PLL output */
414 /* Figure which pll to use */
415 mfcpr(CPR0_PLLC, reg);
416 temp = (reg & PLLC_SRC_MASK) >> 29;
417 if (!temp) /* PLLOUTA */
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
420 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
422 else if (temp == 1) /* CPU output */
423 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
425 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
427 /* Now calculate the individual clocks */
428 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
429 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
430 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
431 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
432 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
433 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
434 sysInfo->freqUART = sysInfo->freqPLB;
436 /* Figure which timer source to use */
437 if (mfspr(SPRN_CCR1) & 0x0080) {
438 /* External Clock, assume same as SYS_CLK */
439 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
440 if (CONFIG_SYS_CLK_FREQ > temp)
441 sysInfo->freqTmrClk = temp;
443 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
445 else /* Internal clock */
446 sysInfo->freqTmrClk = sysInfo->freqProcessor;
449 /********************************************
451 * return PCI bus freq in Hz
452 *********************************************/
453 ulong get_PCI_freq (void)
456 get_sys_info (&sys_info);
457 return sys_info.freqPCI;
460 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
461 && !defined(CONFIG_XILINX_440)
462 void get_sys_info (sys_info_t * sysInfo)
468 /* Extract configured divisors */
469 strp0 = mfdcr( CPC0_STRP0 );
470 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
471 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
472 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
473 sysInfo->pllFbkDiv = temp ? temp : 16;
474 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
475 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
477 /* Calculate 'M' based on feedback source */
478 if( strp0 & PLLSYS0_EXTSL_MASK )
479 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
481 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
483 /* Now calculate the individual clocks */
484 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
485 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
486 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
487 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
488 sysInfo->freqPLB >>= 1;
489 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
490 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
491 sysInfo->freqUART = sysInfo->freqPLB;
495 #if !defined(CONFIG_XILINX_440)
496 void get_sys_info (sys_info_t * sysInfo)
504 unsigned long prbdv0;
506 #if defined(CONFIG_YUCCA)
507 unsigned long sys_freq;
508 unsigned long sys_per=0;
510 unsigned long pci_clock_per;
511 unsigned long sdr_ddrpll;
513 /*-------------------------------------------------------------------------+
514 | Get the system clock period.
515 +-------------------------------------------------------------------------*/
516 sys_per = determine_sysper();
518 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
520 /*-------------------------------------------------------------------------+
521 | Calculate the system clock speed from the period.
522 +-------------------------------------------------------------------------*/
523 sys_freq = (ONE_BILLION / sys_per) * 1000;
526 /* Extract configured divisors */
527 mfsdr( SDR0_SDSTP0,strp0 );
528 mfsdr( SDR0_SDSTP1,strp1 );
530 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
531 sysInfo->pllFwdDivA = temp ? temp : 16 ;
532 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
533 sysInfo->pllFwdDivB = temp ? temp: 8 ;
534 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
535 sysInfo->pllFbkDiv = temp ? temp : 32;
536 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
537 sysInfo->pllOpbDiv = temp ? temp : 4;
538 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
539 sysInfo->pllExtBusDiv = temp ? temp : 4;
540 prbdv0 = (strp0 >> 2) & 0x7;
542 /* Calculate 'M' based on feedback source */
543 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
544 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
545 lfdiv = temp1 ? temp1 : 64;
546 if (temp == 0) { /* PLL output */
547 /* Figure which pll to use */
548 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
552 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
554 else if (temp == 1) /* CPU output */
555 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
557 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
559 /* Now calculate the individual clocks */
560 #if defined(CONFIG_YUCCA)
561 sysInfo->freqVCOMhz = (m * sys_freq) ;
563 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
565 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
566 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
567 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
568 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
570 #if defined(CONFIG_YUCCA)
571 /* Determine PCI Clock Period */
572 pci_clock_per = determine_pci_clock_per();
573 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
574 mfsdr(SDR0_DDR0, sdr_ddrpll);
575 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
578 sysInfo->freqUART = sysInfo->freqPLB;
582 #endif /* CONFIG_XILINX_440 */
584 #if defined(CONFIG_YUCCA)
585 unsigned long determine_sysper(void)
587 unsigned int fpga_clocking_reg;
588 unsigned int master_clock_selection;
589 unsigned long master_clock_per = 0;
590 unsigned long fb_div_selection;
591 unsigned int vco_div_reg_value;
592 unsigned long vco_div_selection;
593 unsigned long sys_per = 0;
596 /*-------------------------------------------------------------------------+
597 | Read FPGA reg 0 and reg 1 to get FPGA reg information
598 +-------------------------------------------------------------------------*/
599 fpga_clocking_reg = in16(FPGA_REG16);
602 /* Determine Master Clock Source Selection */
603 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
605 switch(master_clock_selection) {
606 case FPGA_REG16_MASTER_CLK_66_66:
607 master_clock_per = PERIOD_66_66MHZ;
609 case FPGA_REG16_MASTER_CLK_50:
610 master_clock_per = PERIOD_50_00MHZ;
612 case FPGA_REG16_MASTER_CLK_33_33:
613 master_clock_per = PERIOD_33_33MHZ;
615 case FPGA_REG16_MASTER_CLK_25:
616 master_clock_per = PERIOD_25_00MHZ;
618 case FPGA_REG16_MASTER_CLK_EXT:
619 if ((extClkVal==EXTCLK_33_33)
620 && (extClkVal==EXTCLK_50)
621 && (extClkVal==EXTCLK_66_66)
622 && (extClkVal==EXTCLK_83)) {
623 /* calculate master clock period from external clock value */
624 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
627 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
633 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
638 /* Determine FB divisors values */
639 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
640 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
641 fb_div_selection = FPGA_FB_DIV_6;
643 fb_div_selection = FPGA_FB_DIV_12;
645 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
646 fb_div_selection = FPGA_FB_DIV_10;
648 fb_div_selection = FPGA_FB_DIV_20;
651 /* Determine VCO divisors values */
652 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
654 switch(vco_div_reg_value) {
655 case FPGA_REG16_VCO_DIV_4:
656 vco_div_selection = FPGA_VCO_DIV_4;
658 case FPGA_REG16_VCO_DIV_6:
659 vco_div_selection = FPGA_VCO_DIV_6;
661 case FPGA_REG16_VCO_DIV_8:
662 vco_div_selection = FPGA_VCO_DIV_8;
664 case FPGA_REG16_VCO_DIV_10:
666 vco_div_selection = FPGA_VCO_DIV_10;
670 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
671 switch(master_clock_per) {
672 case PERIOD_25_00MHZ:
673 if (fb_div_selection == FPGA_FB_DIV_12) {
674 if (vco_div_selection == FPGA_VCO_DIV_4)
675 sys_per = PERIOD_75_00MHZ;
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_50_00MHZ;
680 case PERIOD_33_33MHZ:
681 if (fb_div_selection == FPGA_FB_DIV_6) {
682 if (vco_div_selection == FPGA_VCO_DIV_4)
683 sys_per = PERIOD_50_00MHZ;
684 if (vco_div_selection == FPGA_VCO_DIV_6)
685 sys_per = PERIOD_33_33MHZ;
687 if (fb_div_selection == FPGA_FB_DIV_10) {
688 if (vco_div_selection == FPGA_VCO_DIV_4)
689 sys_per = PERIOD_83_33MHZ;
690 if (vco_div_selection == FPGA_VCO_DIV_10)
691 sys_per = PERIOD_33_33MHZ;
693 if (fb_div_selection == FPGA_FB_DIV_12) {
694 if (vco_div_selection == FPGA_VCO_DIV_4)
695 sys_per = PERIOD_100_00MHZ;
696 if (vco_div_selection == FPGA_VCO_DIV_6)
697 sys_per = PERIOD_66_66MHZ;
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_50_00MHZ;
702 case PERIOD_50_00MHZ:
703 if (fb_div_selection == FPGA_FB_DIV_6) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_75_00MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_6)
707 sys_per = PERIOD_50_00MHZ;
709 if (fb_div_selection == FPGA_FB_DIV_10) {
710 if (vco_div_selection == FPGA_VCO_DIV_6)
711 sys_per = PERIOD_83_33MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_10)
713 sys_per = PERIOD_50_00MHZ;
715 if (fb_div_selection == FPGA_FB_DIV_12) {
716 if (vco_div_selection == FPGA_VCO_DIV_6)
717 sys_per = PERIOD_100_00MHZ;
718 if (vco_div_selection == FPGA_VCO_DIV_8)
719 sys_per = PERIOD_75_00MHZ;
722 case PERIOD_66_66MHZ:
723 if (fb_div_selection == FPGA_FB_DIV_6) {
724 if (vco_div_selection == FPGA_VCO_DIV_4)
725 sys_per = PERIOD_100_00MHZ;
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_66_66MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_8)
729 sys_per = PERIOD_50_00MHZ;
731 if (fb_div_selection == FPGA_FB_DIV_10) {
732 if (vco_div_selection == FPGA_VCO_DIV_8)
733 sys_per = PERIOD_83_33MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_10)
735 sys_per = PERIOD_66_66MHZ;
737 if (fb_div_selection == FPGA_FB_DIV_12) {
738 if (vco_div_selection == FPGA_VCO_DIV_8)
739 sys_per = PERIOD_100_00MHZ;
747 /* Other combinations are not supported */
748 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
752 /* calcul system clock without cheking */
753 /* if engineering option clock no check is selected */
754 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
755 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
761 /*-------------------------------------------------------------------------+
762 | determine_pci_clock_per.
763 +-------------------------------------------------------------------------*/
764 unsigned long determine_pci_clock_per(void)
766 unsigned long pci_clock_selection, pci_period;
768 /*-------------------------------------------------------------------------+
769 | Read FPGA reg 6 to get PCI 0 FPGA reg information
770 +-------------------------------------------------------------------------*/
771 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
774 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
776 switch (pci_clock_selection) {
777 case FPGA_REG16_PCI0_CLK_133_33:
778 pci_period = PERIOD_133_33MHZ;
780 case FPGA_REG16_PCI0_CLK_100:
781 pci_period = PERIOD_100_00MHZ;
783 case FPGA_REG16_PCI0_CLK_66_66:
784 pci_period = PERIOD_66_66MHZ;
787 pci_period = PERIOD_33_33MHZ;;
795 #elif defined(CONFIG_XILINX_405)
796 extern void get_sys_info (sys_info_t * sysInfo);
797 extern ulong get_PCI_freq (void);
799 #elif defined(CONFIG_405)
801 void get_sys_info (sys_info_t * sysInfo)
803 sysInfo->freqVCOMhz=3125000;
804 sysInfo->freqProcessor=12*1000*1000;
805 sysInfo->freqPLB=50*1000*1000;
806 sysInfo->freqPCI=66*1000*1000;
809 #elif defined(CONFIG_405EP)
810 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
812 unsigned long pllmr0;
813 unsigned long pllmr1;
814 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
816 unsigned long pllmr0_ccdv;
819 * Read PLL Mode registers
821 pllmr0 = mfdcr (CPC0_PLLMR0);
822 pllmr1 = mfdcr (CPC0_PLLMR1);
825 * Determine forward divider A
827 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
830 * Determine forward divider B (should be equal to A)
832 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
837 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
838 if (sysInfo->pllFbkDiv == 0)
839 sysInfo->pllFbkDiv = 16;
844 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
849 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
852 * Determine EXTBUS_DIV.
854 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
859 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
862 * Determine the M factor
864 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
867 * Determine VCO clock frequency
869 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
870 (unsigned long long)sysClkPeriodPs;
873 * Determine CPU clock frequency
875 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
876 if (pllmr1 & PLLMR1_SSCS_MASK) {
878 * This is true if FWDVA == FWDVB:
879 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
882 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
883 / sysInfo->pllFwdDiv / pllmr0_ccdv;
885 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
889 * Determine PLB clock frequency
891 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
893 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
895 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
897 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
901 /********************************************
903 * return PCI bus freq in Hz
904 *********************************************/
905 ulong get_PCI_freq (void)
908 PPC4xx_SYS_INFO sys_info;
910 get_sys_info (&sys_info);
911 val = sys_info.freqPLB / sys_info.pllPciDiv;
915 #elif defined(CONFIG_405EZ)
916 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
918 unsigned long cpr_plld;
919 unsigned long cpr_pllc;
920 unsigned long cpr_primad;
921 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
922 unsigned long primad_cpudv;
924 unsigned long plloutb;
927 * Read PLL Mode registers
929 mfcpr(CPR0_PLLD, cpr_plld);
930 mfcpr(CPR0_PLLC, cpr_pllc);
933 * Determine forward divider A
935 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
938 * Determine forward divider B
940 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
941 if (sysInfo->pllFwdDivB == 0)
942 sysInfo->pllFwdDivB = 8;
947 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
948 if (sysInfo->pllFbkDiv == 0)
949 sysInfo->pllFbkDiv = 256;
952 * Read CPR_PRIMAD register
954 mfcpr(CPR0_PRIMAD, cpr_primad);
959 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
960 if (sysInfo->pllPlbDiv == 0)
961 sysInfo->pllPlbDiv = 16;
964 * Determine EXTBUS_DIV.
966 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
967 if (sysInfo->pllExtBusDiv == 0)
968 sysInfo->pllExtBusDiv = 16;
973 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
974 if (sysInfo->pllOpbDiv == 0)
975 sysInfo->pllOpbDiv = 16;
978 * Determine the M factor
980 if (cpr_pllc & PLLC_SRC_MASK)
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
983 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
986 * Determine VCO clock frequency
988 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
989 (unsigned long long)sysClkPeriodPs;
992 * Determine CPU clock frequency
994 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
995 if (primad_cpudv == 0)
998 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
999 sysInfo->pllFwdDiv / primad_cpudv;
1002 * Determine PLB clock frequency
1004 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1005 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1007 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1010 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1011 sysInfo->pllExtBusDiv;
1013 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1014 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1015 sysInfo->pllFwdDivB);
1016 sysInfo->freqUART = plloutb;
1019 #elif defined(CONFIG_405EX)
1022 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1023 * We need the specs!!!!
1025 static unsigned char get_fbdv(unsigned char index)
1027 unsigned char ret = 0;
1028 /* This is table should be 256 bytes.
1029 * Only take first 52 values.
1031 unsigned char fbdv_tb[] = {
1032 0x00, 0xff, 0x7f, 0xfd,
1033 0x7a, 0xf5, 0x6a, 0xd5,
1034 0x2a, 0xd4, 0x29, 0xd3,
1035 0x26, 0xcc, 0x19, 0xb3,
1036 0x67, 0xce, 0x1d, 0xbb,
1037 0x77, 0xee, 0x5d, 0xba,
1038 0x74, 0xe9, 0x52, 0xa5,
1039 0x4b, 0x96, 0x2c, 0xd8,
1040 0x31, 0xe3, 0x46, 0x8d,
1041 0x1b, 0xb7, 0x6f, 0xde,
1042 0x3d, 0xfb, 0x76, 0xed,
1043 0x5a, 0xb5, 0x6b, 0xd6,
1044 0x2d, 0xdb, 0x36, 0xec,
1048 if ((index & 0x7f) == 0)
1050 while (ret < sizeof (fbdv_tb)) {
1051 if (fbdv_tb[ret] == index)
1060 #define PLL_FBK_PLL_LOCAL 0
1061 #define PLL_FBK_CPU 1
1062 #define PLL_FBK_PERCLK 5
1064 void get_sys_info (sys_info_t * sysInfo)
1066 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1067 unsigned long m = 1;
1069 unsigned char fwdva[16] = {
1070 1, 2, 14, 9, 4, 11, 16, 13,
1071 12, 5, 6, 15, 10, 7, 8, 3,
1073 unsigned char sel, cpudv0, plb2xDiv;
1075 mfcpr(CPR0_PLLD, tmp);
1078 * Determine forward divider A
1080 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1083 * Determine FBK_DIV.
1085 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1090 sysInfo->pllPlbDiv = 2;
1095 mfcpr(CPR0_PERD, tmp);
1096 tmp = (tmp >> 24) & 0x03;
1097 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1102 mfcpr(CPR0_OPBD0, tmp);
1103 tmp = (tmp >> 24) & 0x03;
1104 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1106 /* Determine PLB2XDV0 */
1107 mfcpr(CPR0_PLBD, tmp);
1108 tmp = (tmp >> 16) & 0x07;
1109 plb2xDiv = (tmp == 0) ? 8 : tmp;
1111 /* Determine CPUDV0 */
1112 mfcpr(CPR0_CPUD, tmp);
1113 tmp = (tmp >> 24) & 0x07;
1114 cpudv0 = (tmp == 0) ? 8 : tmp;
1116 /* Determine SEL(5:7) in CPR0_PLLC */
1117 mfcpr(CPR0_PLLC, tmp);
1118 sel = (tmp >> 24) & 0x07;
1121 * Determine the M factor
1122 * PLL local: M = FBDV
1123 * CPU clock: M = FBDV * FWDVA * CPUDV0
1124 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1129 m = sysInfo->pllFwdDiv * cpudv0;
1131 case PLL_FBK_PERCLK:
1132 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1133 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1135 case PLL_FBK_PLL_LOCAL:
1138 printf("%s unknown m\n", __FUNCTION__);
1142 m *= sysInfo->pllFbkDiv;
1145 * Determine VCO clock frequency
1147 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1148 (unsigned long long)sysClkPeriodPs;
1151 * Determine CPU clock frequency
1153 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1156 * Determine PLB clock frequency, ddr1x should be the same
1158 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1159 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1160 sysInfo->freqDDR = sysInfo->freqPLB;
1161 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1162 sysInfo->freqUART = sysInfo->freqPLB;
1167 int get_clocks (void)
1169 sys_info_t sys_info;
1171 get_sys_info (&sys_info);
1172 gd->cpu_clk = sys_info.freqProcessor;
1173 gd->bus_clk = sys_info.freqPLB;
1179 /********************************************
1181 * return PLB bus freq in Hz
1182 *********************************************/
1183 ulong get_bus_freq (ulong dummy)
1187 #if defined(CONFIG_405GP) || \
1188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1191 sys_info_t sys_info;
1193 get_sys_info (&sys_info);
1194 val = sys_info.freqPLB;
1196 # error get_bus_freq() not implemented
1202 ulong get_OPB_freq (void)
1204 PPC4xx_SYS_INFO sys_info;
1206 get_sys_info (&sys_info);
1208 return sys_info.freqOPB;