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 #if defined(CONFIG_405GP)
24 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
27 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
33 * Read PLL Mode register
35 pllmr = mfdcr (CPC0_PLLMR);
38 * Read Pin Strapping register
40 psr = mfdcr (CPC0_PSR);
45 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
50 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
51 if (sysInfo->pllFbkDiv == 0) {
52 sysInfo->pllFbkDiv = 16;
58 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
63 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
66 * Determine EXTBUS_DIV.
68 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
73 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
76 * Check if PPC405GPr used (mask minor revision field)
78 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
80 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
82 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
85 * Determine factor m depending on PLL feedback clock source
87 if (!(psr & PSR_PCI_ASYNC_EN)) {
88 if (psr & PSR_NEW_MODE_EN) {
90 * sync pci clock used as feedback (new mode)
92 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
95 * sync pci clock used as feedback (legacy mode)
97 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
99 } else if (psr & PSR_NEW_MODE_EN) {
100 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
102 * PerClk used as feedback (new mode)
104 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
107 * CPU clock used as feedback (new mode)
109 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
111 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
113 * PerClk used as feedback (legacy mode)
115 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
118 * PLB clock used as feedback (legacy mode)
120 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
123 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
124 (unsigned long long)sysClkPeriodPs;
125 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
126 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
129 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
130 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
131 * to make sure it is within the proper range.
132 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
133 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
135 if (sysInfo->pllFwdDiv == 1) {
136 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
137 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
139 sysInfo->freqVCOHz = ( 1000000000000LL *
140 (unsigned long long)sysInfo->pllFwdDiv *
141 (unsigned long long)sysInfo->pllFbkDiv *
142 (unsigned long long)sysInfo->pllPlbDiv
143 ) / (unsigned long long)sysClkPeriodPs;
144 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
145 sysInfo->pllFbkDiv)) * 10000;
146 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
150 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
151 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
152 sysInfo->freqUART = sysInfo->freqProcessor;
156 /********************************************
158 * return PCI bus freq in Hz
159 *********************************************/
160 ulong get_PCI_freq (void)
163 PPC4xx_SYS_INFO sys_info;
165 get_sys_info (&sys_info);
166 val = sys_info.freqPLB / sys_info.pllPciDiv;
171 #elif defined(CONFIG_440)
173 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
174 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
175 static u8 pll_fwdv_multi_bits[] = {
176 /* values for: 1 - 16 */
177 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
178 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
181 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
185 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
186 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
192 static u8 pll_fbdv_multi_bits[] = {
193 /* values for: 1 - 100 */
194 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
195 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
196 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
197 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
198 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
199 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
200 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
201 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
202 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
203 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
204 /* values for: 101 - 200 */
205 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
206 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
207 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
208 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
209 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
210 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
211 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
212 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
213 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
214 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
215 /* values for: 201 - 255 */
216 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
217 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
218 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
219 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
220 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
221 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
224 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
228 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
229 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
235 #if defined(CONFIG_APM821XX)
237 void get_sys_info(sys_info_t *sysInfo)
243 unsigned long plb2dv;
244 unsigned long ddr2dv;
246 /* Calculate Forward divisor A and Feeback divisor */
247 mfcpr(CPR0_PLLD, plld);
249 temp = CPR0_PLLD_FWDVA(plld);
250 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
252 temp = CPR0_PLLD_FDV(plld);
253 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
255 /* Calculate OPB clock divisor */
256 mfcpr(CPR0_OPBD, temp);
257 temp = CPR0_OPBD_OPBDV(temp);
258 sysInfo->pllOpbDiv = temp ? temp : 4;
260 /* Calculate Peripheral clock divisor */
261 mfcpr(CPR0_PERD, temp);
262 temp = CPR0_PERD_PERDV(temp);
263 sysInfo->pllExtBusDiv = temp ? temp : 4;
265 /* Calculate CPU clock divisor */
266 mfcpr(CPR0_CPUD, temp);
267 temp = CPR0_CPUD_CPUDV(temp);
268 cpudv = temp ? temp : 8;
270 /* Calculate PLB2 clock divisor */
271 mfcpr(CPR0_PLB2D, temp);
272 temp = CPR0_PLB2D_PLB2DV(temp);
273 plb2dv = temp ? temp : 4;
275 /* Calculate DDR2 clock divisor */
276 mfcpr(CPR0_DDR2D, temp);
277 temp = CPR0_DDR2D_DDR2DV(temp);
278 ddr2dv = temp ? temp : 4;
280 /* Calculate 'M' based on feedback source */
281 mfcpr(CPR0_PLLC, temp);
282 temp = CPR0_PLLC_SEL(temp);
284 /* PLL internal feedback */
285 mul = sysInfo->pllFbkDiv;
287 /* PLL PerClk feedback */
288 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
289 * plb2dv * 2 * sysInfo->pllOpbDiv *
290 sysInfo->pllExtBusDiv;
293 /* Now calculate the individual clocks */
294 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
295 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
296 sysInfo->pllFwdDivA / cpudv;
297 sysInfo->freqPLB = sysInfo->freqVCOMhz /
298 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
299 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
300 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
301 sysInfo->freqDDR = sysInfo->freqVCOMhz /
302 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
303 sysInfo->freqUART = sysInfo->freqPLB;
308 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
311 void get_sys_info (sys_info_t * sysInfo)
317 unsigned long plbedv0;
319 /* Extract configured divisors */
320 mfsdr(SDR0_SDSTP0, strp0);
321 mfsdr(SDR0_SDSTP1, strp1);
323 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
324 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
326 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
327 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
329 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
330 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
332 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
333 sysInfo->pllOpbDiv = temp ? temp : 4;
335 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
336 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
337 sysInfo->pllExtBusDiv = temp ? temp : 4;
339 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
340 plbedv0 = temp ? temp: 8;
342 /* Calculate 'M' based on feedback source */
343 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
345 /* PLL internal feedback */
346 m = sysInfo->pllFbkDiv;
348 /* PLL PerClk feedback */
349 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
350 sysInfo->pllExtBusDiv;
353 /* Now calculate the individual clocks */
354 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
355 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
356 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
357 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
358 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
359 sysInfo->freqDDR = sysInfo->freqPLB;
360 sysInfo->freqUART = sysInfo->freqPLB;
366 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
367 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
368 void get_sys_info (sys_info_t *sysInfo)
374 unsigned long prbdv0;
376 WARNING: ASSUMES the following:
382 /* Decode CPR0_PLLD0 for divisors */
383 mfcpr(CPR0_PLLD, reg);
384 temp = (reg & PLLD_FWDVA_MASK) >> 16;
385 sysInfo->pllFwdDivA = temp ? temp : 16;
386 temp = (reg & PLLD_FWDVB_MASK) >> 8;
387 sysInfo->pllFwdDivB = temp ? temp: 8 ;
388 temp = (reg & PLLD_FBDV_MASK) >> 24;
389 sysInfo->pllFbkDiv = temp ? temp : 32;
390 lfdiv = reg & PLLD_LFBDV_MASK;
392 mfcpr(CPR0_OPBD0, reg);
393 temp = (reg & OPBDDV_MASK) >> 24;
394 sysInfo->pllOpbDiv = temp ? temp : 4;
396 mfcpr(CPR0_PERD, reg);
397 temp = (reg & PERDV_MASK) >> 24;
398 sysInfo->pllExtBusDiv = temp ? temp : 8;
400 mfcpr(CPR0_PRIMBD0, reg);
401 temp = (reg & PRBDV_MASK) >> 24;
402 prbdv0 = temp ? temp : 8;
404 mfcpr(CPR0_SPCID, reg);
405 temp = (reg & SPCID_MASK) >> 24;
406 sysInfo->pllPciDiv = temp ? temp : 4;
408 /* Calculate 'M' based on feedback source */
409 mfsdr(SDR0_SDSTP0, reg);
410 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
411 if (temp == 0) { /* PLL output */
412 /* Figure which pll to use */
413 mfcpr(CPR0_PLLC, reg);
414 temp = (reg & PLLC_SRC_MASK) >> 29;
415 if (!temp) /* PLLOUTA */
416 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
420 else if (temp == 1) /* CPU output */
421 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
423 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
425 /* Now calculate the individual clocks */
426 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
427 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
428 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
429 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
430 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
431 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
432 sysInfo->freqUART = sysInfo->freqPLB;
434 /* Figure which timer source to use */
435 if (mfspr(SPRN_CCR1) & 0x0080) {
436 /* External Clock, assume same as SYS_CLK */
437 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
438 if (CONFIG_SYS_CLK_FREQ > temp)
439 sysInfo->freqTmrClk = temp;
441 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
443 else /* Internal clock */
444 sysInfo->freqTmrClk = sysInfo->freqProcessor;
447 /********************************************
449 * return PCI bus freq in Hz
450 *********************************************/
451 ulong get_PCI_freq (void)
454 get_sys_info (&sys_info);
455 return sys_info.freqPCI;
458 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
459 && !defined(CONFIG_XILINX_440)
460 void get_sys_info (sys_info_t * sysInfo)
466 /* Extract configured divisors */
467 strp0 = mfdcr( CPC0_STRP0 );
468 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
469 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
470 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
471 sysInfo->pllFbkDiv = temp ? temp : 16;
472 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
473 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
475 /* Calculate 'M' based on feedback source */
476 if( strp0 & PLLSYS0_EXTSL_MASK )
477 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
479 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
481 /* Now calculate the individual clocks */
482 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
483 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
484 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
485 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
486 sysInfo->freqPLB >>= 1;
487 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
488 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
489 sysInfo->freqUART = sysInfo->freqPLB;
493 #if !defined(CONFIG_XILINX_440)
494 void get_sys_info (sys_info_t * sysInfo)
502 unsigned long prbdv0;
504 #if defined(CONFIG_YUCCA)
505 unsigned long sys_freq;
506 unsigned long sys_per=0;
508 unsigned long pci_clock_per;
509 unsigned long sdr_ddrpll;
511 /*-------------------------------------------------------------------------+
512 | Get the system clock period.
513 +-------------------------------------------------------------------------*/
514 sys_per = determine_sysper();
516 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
518 /*-------------------------------------------------------------------------+
519 | Calculate the system clock speed from the period.
520 +-------------------------------------------------------------------------*/
521 sys_freq = (ONE_BILLION / sys_per) * 1000;
524 /* Extract configured divisors */
525 mfsdr( SDR0_SDSTP0,strp0 );
526 mfsdr( SDR0_SDSTP1,strp1 );
528 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
529 sysInfo->pllFwdDivA = temp ? temp : 16 ;
530 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
531 sysInfo->pllFwdDivB = temp ? temp: 8 ;
532 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
533 sysInfo->pllFbkDiv = temp ? temp : 32;
534 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
535 sysInfo->pllOpbDiv = temp ? temp : 4;
536 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
537 sysInfo->pllExtBusDiv = temp ? temp : 4;
538 prbdv0 = (strp0 >> 2) & 0x7;
540 /* Calculate 'M' based on feedback source */
541 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
542 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
543 lfdiv = temp1 ? temp1 : 64;
544 if (temp == 0) { /* PLL output */
545 /* Figure which pll to use */
546 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
548 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
552 else if (temp == 1) /* CPU output */
553 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
555 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
557 /* Now calculate the individual clocks */
558 #if defined(CONFIG_YUCCA)
559 sysInfo->freqVCOMhz = (m * sys_freq) ;
561 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
563 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
564 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
565 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
566 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
568 #if defined(CONFIG_YUCCA)
569 /* Determine PCI Clock Period */
570 pci_clock_per = determine_pci_clock_per();
571 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
572 mfsdr(SDR0_DDR0, sdr_ddrpll);
573 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
576 sysInfo->freqUART = sysInfo->freqPLB;
580 #endif /* CONFIG_XILINX_440 */
582 #if defined(CONFIG_YUCCA)
583 unsigned long determine_sysper(void)
585 unsigned int fpga_clocking_reg;
586 unsigned int master_clock_selection;
587 unsigned long master_clock_per = 0;
588 unsigned long fb_div_selection;
589 unsigned int vco_div_reg_value;
590 unsigned long vco_div_selection;
591 unsigned long sys_per = 0;
594 /*-------------------------------------------------------------------------+
595 | Read FPGA reg 0 and reg 1 to get FPGA reg information
596 +-------------------------------------------------------------------------*/
597 fpga_clocking_reg = in16(FPGA_REG16);
600 /* Determine Master Clock Source Selection */
601 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
603 switch(master_clock_selection) {
604 case FPGA_REG16_MASTER_CLK_66_66:
605 master_clock_per = PERIOD_66_66MHZ;
607 case FPGA_REG16_MASTER_CLK_50:
608 master_clock_per = PERIOD_50_00MHZ;
610 case FPGA_REG16_MASTER_CLK_33_33:
611 master_clock_per = PERIOD_33_33MHZ;
613 case FPGA_REG16_MASTER_CLK_25:
614 master_clock_per = PERIOD_25_00MHZ;
616 case FPGA_REG16_MASTER_CLK_EXT:
617 if ((extClkVal==EXTCLK_33_33)
618 && (extClkVal==EXTCLK_50)
619 && (extClkVal==EXTCLK_66_66)
620 && (extClkVal==EXTCLK_83)) {
621 /* calculate master clock period from external clock value */
622 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
625 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
631 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
636 /* Determine FB divisors values */
637 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
638 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
639 fb_div_selection = FPGA_FB_DIV_6;
641 fb_div_selection = FPGA_FB_DIV_12;
643 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
644 fb_div_selection = FPGA_FB_DIV_10;
646 fb_div_selection = FPGA_FB_DIV_20;
649 /* Determine VCO divisors values */
650 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
652 switch(vco_div_reg_value) {
653 case FPGA_REG16_VCO_DIV_4:
654 vco_div_selection = FPGA_VCO_DIV_4;
656 case FPGA_REG16_VCO_DIV_6:
657 vco_div_selection = FPGA_VCO_DIV_6;
659 case FPGA_REG16_VCO_DIV_8:
660 vco_div_selection = FPGA_VCO_DIV_8;
662 case FPGA_REG16_VCO_DIV_10:
664 vco_div_selection = FPGA_VCO_DIV_10;
668 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
669 switch(master_clock_per) {
670 case PERIOD_25_00MHZ:
671 if (fb_div_selection == FPGA_FB_DIV_12) {
672 if (vco_div_selection == FPGA_VCO_DIV_4)
673 sys_per = PERIOD_75_00MHZ;
674 if (vco_div_selection == FPGA_VCO_DIV_6)
675 sys_per = PERIOD_50_00MHZ;
678 case PERIOD_33_33MHZ:
679 if (fb_div_selection == FPGA_FB_DIV_6) {
680 if (vco_div_selection == FPGA_VCO_DIV_4)
681 sys_per = PERIOD_50_00MHZ;
682 if (vco_div_selection == FPGA_VCO_DIV_6)
683 sys_per = PERIOD_33_33MHZ;
685 if (fb_div_selection == FPGA_FB_DIV_10) {
686 if (vco_div_selection == FPGA_VCO_DIV_4)
687 sys_per = PERIOD_83_33MHZ;
688 if (vco_div_selection == FPGA_VCO_DIV_10)
689 sys_per = PERIOD_33_33MHZ;
691 if (fb_div_selection == FPGA_FB_DIV_12) {
692 if (vco_div_selection == FPGA_VCO_DIV_4)
693 sys_per = PERIOD_100_00MHZ;
694 if (vco_div_selection == FPGA_VCO_DIV_6)
695 sys_per = PERIOD_66_66MHZ;
696 if (vco_div_selection == FPGA_VCO_DIV_8)
697 sys_per = PERIOD_50_00MHZ;
700 case PERIOD_50_00MHZ:
701 if (fb_div_selection == FPGA_FB_DIV_6) {
702 if (vco_div_selection == FPGA_VCO_DIV_4)
703 sys_per = PERIOD_75_00MHZ;
704 if (vco_div_selection == FPGA_VCO_DIV_6)
705 sys_per = PERIOD_50_00MHZ;
707 if (fb_div_selection == FPGA_FB_DIV_10) {
708 if (vco_div_selection == FPGA_VCO_DIV_6)
709 sys_per = PERIOD_83_33MHZ;
710 if (vco_div_selection == FPGA_VCO_DIV_10)
711 sys_per = PERIOD_50_00MHZ;
713 if (fb_div_selection == FPGA_FB_DIV_12) {
714 if (vco_div_selection == FPGA_VCO_DIV_6)
715 sys_per = PERIOD_100_00MHZ;
716 if (vco_div_selection == FPGA_VCO_DIV_8)
717 sys_per = PERIOD_75_00MHZ;
720 case PERIOD_66_66MHZ:
721 if (fb_div_selection == FPGA_FB_DIV_6) {
722 if (vco_div_selection == FPGA_VCO_DIV_4)
723 sys_per = PERIOD_100_00MHZ;
724 if (vco_div_selection == FPGA_VCO_DIV_6)
725 sys_per = PERIOD_66_66MHZ;
726 if (vco_div_selection == FPGA_VCO_DIV_8)
727 sys_per = PERIOD_50_00MHZ;
729 if (fb_div_selection == FPGA_FB_DIV_10) {
730 if (vco_div_selection == FPGA_VCO_DIV_8)
731 sys_per = PERIOD_83_33MHZ;
732 if (vco_div_selection == FPGA_VCO_DIV_10)
733 sys_per = PERIOD_66_66MHZ;
735 if (fb_div_selection == FPGA_FB_DIV_12) {
736 if (vco_div_selection == FPGA_VCO_DIV_8)
737 sys_per = PERIOD_100_00MHZ;
745 /* Other combinations are not supported */
746 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
750 /* calcul system clock without cheking */
751 /* if engineering option clock no check is selected */
752 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
753 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
759 /*-------------------------------------------------------------------------+
760 | determine_pci_clock_per.
761 +-------------------------------------------------------------------------*/
762 unsigned long determine_pci_clock_per(void)
764 unsigned long pci_clock_selection, pci_period;
766 /*-------------------------------------------------------------------------+
767 | Read FPGA reg 6 to get PCI 0 FPGA reg information
768 +-------------------------------------------------------------------------*/
769 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
772 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
774 switch (pci_clock_selection) {
775 case FPGA_REG16_PCI0_CLK_133_33:
776 pci_period = PERIOD_133_33MHZ;
778 case FPGA_REG16_PCI0_CLK_100:
779 pci_period = PERIOD_100_00MHZ;
781 case FPGA_REG16_PCI0_CLK_66_66:
782 pci_period = PERIOD_66_66MHZ;
785 pci_period = PERIOD_33_33MHZ;;
793 #elif defined(CONFIG_XILINX_405)
794 extern void get_sys_info (sys_info_t * sysInfo);
795 extern ulong get_PCI_freq (void);
797 #elif defined(CONFIG_405)
799 void get_sys_info (sys_info_t * sysInfo)
801 sysInfo->freqVCOMhz=3125000;
802 sysInfo->freqProcessor=12*1000*1000;
803 sysInfo->freqPLB=50*1000*1000;
804 sysInfo->freqPCI=66*1000*1000;
807 #elif defined(CONFIG_405EP)
808 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
810 unsigned long pllmr0;
811 unsigned long pllmr1;
812 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
814 unsigned long pllmr0_ccdv;
817 * Read PLL Mode registers
819 pllmr0 = mfdcr (CPC0_PLLMR0);
820 pllmr1 = mfdcr (CPC0_PLLMR1);
823 * Determine forward divider A
825 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
828 * Determine forward divider B (should be equal to A)
830 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
835 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
836 if (sysInfo->pllFbkDiv == 0)
837 sysInfo->pllFbkDiv = 16;
842 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
847 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
850 * Determine EXTBUS_DIV.
852 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
857 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
860 * Determine the M factor
862 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
865 * Determine VCO clock frequency
867 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
868 (unsigned long long)sysClkPeriodPs;
871 * Determine CPU clock frequency
873 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
874 if (pllmr1 & PLLMR1_SSCS_MASK) {
876 * This is true if FWDVA == FWDVB:
877 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
880 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
881 / sysInfo->pllFwdDiv / pllmr0_ccdv;
883 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
887 * Determine PLB clock frequency
889 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
891 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
893 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
895 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
899 /********************************************
901 * return PCI bus freq in Hz
902 *********************************************/
903 ulong get_PCI_freq (void)
906 PPC4xx_SYS_INFO sys_info;
908 get_sys_info (&sys_info);
909 val = sys_info.freqPLB / sys_info.pllPciDiv;
913 #elif defined(CONFIG_405EZ)
914 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
916 unsigned long cpr_plld;
917 unsigned long cpr_pllc;
918 unsigned long cpr_primad;
919 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
920 unsigned long primad_cpudv;
922 unsigned long plloutb;
925 * Read PLL Mode registers
927 mfcpr(CPR0_PLLD, cpr_plld);
928 mfcpr(CPR0_PLLC, cpr_pllc);
931 * Determine forward divider A
933 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
936 * Determine forward divider B
938 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
939 if (sysInfo->pllFwdDivB == 0)
940 sysInfo->pllFwdDivB = 8;
945 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
946 if (sysInfo->pllFbkDiv == 0)
947 sysInfo->pllFbkDiv = 256;
950 * Read CPR_PRIMAD register
952 mfcpr(CPR0_PRIMAD, cpr_primad);
957 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
958 if (sysInfo->pllPlbDiv == 0)
959 sysInfo->pllPlbDiv = 16;
962 * Determine EXTBUS_DIV.
964 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
965 if (sysInfo->pllExtBusDiv == 0)
966 sysInfo->pllExtBusDiv = 16;
971 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
972 if (sysInfo->pllOpbDiv == 0)
973 sysInfo->pllOpbDiv = 16;
976 * Determine the M factor
978 if (cpr_pllc & PLLC_SRC_MASK)
979 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
984 * Determine VCO clock frequency
986 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
987 (unsigned long long)sysClkPeriodPs;
990 * Determine CPU clock frequency
992 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
993 if (primad_cpudv == 0)
996 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
997 sysInfo->pllFwdDiv / primad_cpudv;
1000 * Determine PLB clock frequency
1002 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1003 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1005 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1008 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1009 sysInfo->pllExtBusDiv;
1011 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1012 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1013 sysInfo->pllFwdDivB);
1014 sysInfo->freqUART = plloutb;
1017 #elif defined(CONFIG_405EX)
1020 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1021 * We need the specs!!!!
1023 static unsigned char get_fbdv(unsigned char index)
1025 unsigned char ret = 0;
1026 /* This is table should be 256 bytes.
1027 * Only take first 52 values.
1029 unsigned char fbdv_tb[] = {
1030 0x00, 0xff, 0x7f, 0xfd,
1031 0x7a, 0xf5, 0x6a, 0xd5,
1032 0x2a, 0xd4, 0x29, 0xd3,
1033 0x26, 0xcc, 0x19, 0xb3,
1034 0x67, 0xce, 0x1d, 0xbb,
1035 0x77, 0xee, 0x5d, 0xba,
1036 0x74, 0xe9, 0x52, 0xa5,
1037 0x4b, 0x96, 0x2c, 0xd8,
1038 0x31, 0xe3, 0x46, 0x8d,
1039 0x1b, 0xb7, 0x6f, 0xde,
1040 0x3d, 0xfb, 0x76, 0xed,
1041 0x5a, 0xb5, 0x6b, 0xd6,
1042 0x2d, 0xdb, 0x36, 0xec,
1046 if ((index & 0x7f) == 0)
1048 while (ret < sizeof (fbdv_tb)) {
1049 if (fbdv_tb[ret] == index)
1058 #define PLL_FBK_PLL_LOCAL 0
1059 #define PLL_FBK_CPU 1
1060 #define PLL_FBK_PERCLK 5
1062 void get_sys_info (sys_info_t * sysInfo)
1064 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1065 unsigned long m = 1;
1067 unsigned char fwdva[16] = {
1068 1, 2, 14, 9, 4, 11, 16, 13,
1069 12, 5, 6, 15, 10, 7, 8, 3,
1071 unsigned char sel, cpudv0, plb2xDiv;
1073 mfcpr(CPR0_PLLD, tmp);
1076 * Determine forward divider A
1078 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1081 * Determine FBK_DIV.
1083 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1088 sysInfo->pllPlbDiv = 2;
1093 mfcpr(CPR0_PERD, tmp);
1094 tmp = (tmp >> 24) & 0x03;
1095 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1100 mfcpr(CPR0_OPBD0, tmp);
1101 tmp = (tmp >> 24) & 0x03;
1102 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1104 /* Determine PLB2XDV0 */
1105 mfcpr(CPR0_PLBD, tmp);
1106 tmp = (tmp >> 16) & 0x07;
1107 plb2xDiv = (tmp == 0) ? 8 : tmp;
1109 /* Determine CPUDV0 */
1110 mfcpr(CPR0_CPUD, tmp);
1111 tmp = (tmp >> 24) & 0x07;
1112 cpudv0 = (tmp == 0) ? 8 : tmp;
1114 /* Determine SEL(5:7) in CPR0_PLLC */
1115 mfcpr(CPR0_PLLC, tmp);
1116 sel = (tmp >> 24) & 0x07;
1119 * Determine the M factor
1120 * PLL local: M = FBDV
1121 * CPU clock: M = FBDV * FWDVA * CPUDV0
1122 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1127 m = sysInfo->pllFwdDiv * cpudv0;
1129 case PLL_FBK_PERCLK:
1130 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1131 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1133 case PLL_FBK_PLL_LOCAL:
1136 printf("%s unknown m\n", __FUNCTION__);
1140 m *= sysInfo->pllFbkDiv;
1143 * Determine VCO clock frequency
1145 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1146 (unsigned long long)sysClkPeriodPs;
1149 * Determine CPU clock frequency
1151 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1154 * Determine PLB clock frequency, ddr1x should be the same
1156 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1157 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1158 sysInfo->freqDDR = sysInfo->freqPLB;
1159 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1160 sysInfo->freqUART = sysInfo->freqPLB;
1165 int get_clocks (void)
1167 sys_info_t sys_info;
1169 get_sys_info (&sys_info);
1170 gd->cpu_clk = sys_info.freqProcessor;
1171 gd->bus_clk = sys_info.freqPLB;
1177 /********************************************
1179 * return PLB bus freq in Hz
1180 *********************************************/
1181 ulong get_bus_freq (ulong dummy)
1185 #if defined(CONFIG_405GP) || \
1186 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1187 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1189 sys_info_t sys_info;
1191 get_sys_info (&sys_info);
1192 val = sys_info.freqPLB;
1194 # error get_bus_freq() not implemented
1200 ulong get_OPB_freq (void)
1202 PPC4xx_SYS_INFO sys_info;
1204 get_sys_info (&sys_info);
1206 return sys_info.freqOPB;