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)
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])
236 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
239 void get_sys_info (sys_info_t * sysInfo)
245 unsigned long plbedv0;
247 /* Extract configured divisors */
248 mfsdr(SDR0_SDSTP0, strp0);
249 mfsdr(SDR0_SDSTP1, strp1);
251 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
254 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
255 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
257 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
258 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
260 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
261 sysInfo->pllOpbDiv = temp ? temp : 4;
263 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
264 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
267 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
268 plbedv0 = temp ? temp: 8;
270 /* Calculate 'M' based on feedback source */
271 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
273 /* PLL internal feedback */
274 m = sysInfo->pllFbkDiv;
276 /* PLL PerClk feedback */
277 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
278 sysInfo->pllExtBusDiv;
281 /* Now calculate the individual clocks */
282 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
283 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
284 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
285 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
286 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
287 sysInfo->freqDDR = sysInfo->freqPLB;
288 sysInfo->freqUART = sysInfo->freqPLB;
293 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
294 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
295 void get_sys_info (sys_info_t *sysInfo)
301 unsigned long prbdv0;
303 WARNING: ASSUMES the following:
309 /* Decode CPR0_PLLD0 for divisors */
310 mfcpr(CPR0_PLLD, reg);
311 temp = (reg & PLLD_FWDVA_MASK) >> 16;
312 sysInfo->pllFwdDivA = temp ? temp : 16;
313 temp = (reg & PLLD_FWDVB_MASK) >> 8;
314 sysInfo->pllFwdDivB = temp ? temp: 8 ;
315 temp = (reg & PLLD_FBDV_MASK) >> 24;
316 sysInfo->pllFbkDiv = temp ? temp : 32;
317 lfdiv = reg & PLLD_LFBDV_MASK;
319 mfcpr(CPR0_OPBD0, reg);
320 temp = (reg & OPBDDV_MASK) >> 24;
321 sysInfo->pllOpbDiv = temp ? temp : 4;
323 mfcpr(CPR0_PERD, reg);
324 temp = (reg & PERDV_MASK) >> 24;
325 sysInfo->pllExtBusDiv = temp ? temp : 8;
327 mfcpr(CPR0_PRIMBD0, reg);
328 temp = (reg & PRBDV_MASK) >> 24;
329 prbdv0 = temp ? temp : 8;
331 mfcpr(CPR0_SPCID, reg);
332 temp = (reg & SPCID_MASK) >> 24;
333 sysInfo->pllPciDiv = temp ? temp : 4;
335 /* Calculate 'M' based on feedback source */
336 mfsdr(SDR0_SDSTP0, reg);
337 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
338 if (temp == 0) { /* PLL output */
339 /* Figure which pll to use */
340 mfcpr(CPR0_PLLC, reg);
341 temp = (reg & PLLC_SRC_MASK) >> 29;
342 if (!temp) /* PLLOUTA */
343 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
345 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
347 else if (temp == 1) /* CPU output */
348 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
350 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
352 /* Now calculate the individual clocks */
353 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
354 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
355 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
356 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
357 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
358 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
359 sysInfo->freqUART = sysInfo->freqPLB;
361 /* Figure which timer source to use */
362 if (mfspr(SPRN_CCR1) & 0x0080) {
363 /* External Clock, assume same as SYS_CLK */
364 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
365 if (CONFIG_SYS_CLK_FREQ > temp)
366 sysInfo->freqTmrClk = temp;
368 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
370 else /* Internal clock */
371 sysInfo->freqTmrClk = sysInfo->freqProcessor;
374 /********************************************
376 * return PCI bus freq in Hz
377 *********************************************/
378 ulong get_PCI_freq (void)
381 get_sys_info (&sys_info);
382 return sys_info.freqPCI;
385 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
386 && !defined(CONFIG_XILINX_440)
387 void get_sys_info (sys_info_t * sysInfo)
393 /* Extract configured divisors */
394 strp0 = mfdcr( CPC0_STRP0 );
395 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
396 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
397 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
398 sysInfo->pllFbkDiv = temp ? temp : 16;
399 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
400 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
402 /* Calculate 'M' based on feedback source */
403 if( strp0 & PLLSYS0_EXTSL_MASK )
404 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
406 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
408 /* Now calculate the individual clocks */
409 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
410 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
411 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
412 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
413 sysInfo->freqPLB >>= 1;
414 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
415 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
416 sysInfo->freqUART = sysInfo->freqPLB;
420 #if !defined(CONFIG_XILINX_440)
421 void get_sys_info (sys_info_t * sysInfo)
429 unsigned long prbdv0;
431 #if defined(CONFIG_YUCCA)
432 unsigned long sys_freq;
433 unsigned long sys_per=0;
435 unsigned long pci_clock_per;
436 unsigned long sdr_ddrpll;
438 /*-------------------------------------------------------------------------+
439 | Get the system clock period.
440 +-------------------------------------------------------------------------*/
441 sys_per = determine_sysper();
443 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
445 /*-------------------------------------------------------------------------+
446 | Calculate the system clock speed from the period.
447 +-------------------------------------------------------------------------*/
448 sys_freq = (ONE_BILLION / sys_per) * 1000;
451 /* Extract configured divisors */
452 mfsdr( SDR0_SDSTP0,strp0 );
453 mfsdr( SDR0_SDSTP1,strp1 );
455 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
456 sysInfo->pllFwdDivA = temp ? temp : 16 ;
457 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
458 sysInfo->pllFwdDivB = temp ? temp: 8 ;
459 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
460 sysInfo->pllFbkDiv = temp ? temp : 32;
461 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
462 sysInfo->pllOpbDiv = temp ? temp : 4;
463 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
464 sysInfo->pllExtBusDiv = temp ? temp : 4;
465 prbdv0 = (strp0 >> 2) & 0x7;
467 /* Calculate 'M' based on feedback source */
468 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
469 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
470 lfdiv = temp1 ? temp1 : 64;
471 if (temp == 0) { /* PLL output */
472 /* Figure which pll to use */
473 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
475 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
477 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
479 else if (temp == 1) /* CPU output */
480 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
482 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
484 /* Now calculate the individual clocks */
485 #if defined(CONFIG_YUCCA)
486 sysInfo->freqVCOMhz = (m * sys_freq) ;
488 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
490 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
491 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
492 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
493 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
495 #if defined(CONFIG_YUCCA)
496 /* Determine PCI Clock Period */
497 pci_clock_per = determine_pci_clock_per();
498 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
499 mfsdr(SDR0_DDR0, sdr_ddrpll);
500 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
503 sysInfo->freqUART = sysInfo->freqPLB;
507 #endif /* CONFIG_XILINX_440 */
509 #if defined(CONFIG_YUCCA)
510 unsigned long determine_sysper(void)
512 unsigned int fpga_clocking_reg;
513 unsigned int master_clock_selection;
514 unsigned long master_clock_per = 0;
515 unsigned long fb_div_selection;
516 unsigned int vco_div_reg_value;
517 unsigned long vco_div_selection;
518 unsigned long sys_per = 0;
521 /*-------------------------------------------------------------------------+
522 | Read FPGA reg 0 and reg 1 to get FPGA reg information
523 +-------------------------------------------------------------------------*/
524 fpga_clocking_reg = in16(FPGA_REG16);
527 /* Determine Master Clock Source Selection */
528 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
530 switch(master_clock_selection) {
531 case FPGA_REG16_MASTER_CLK_66_66:
532 master_clock_per = PERIOD_66_66MHZ;
534 case FPGA_REG16_MASTER_CLK_50:
535 master_clock_per = PERIOD_50_00MHZ;
537 case FPGA_REG16_MASTER_CLK_33_33:
538 master_clock_per = PERIOD_33_33MHZ;
540 case FPGA_REG16_MASTER_CLK_25:
541 master_clock_per = PERIOD_25_00MHZ;
543 case FPGA_REG16_MASTER_CLK_EXT:
544 if ((extClkVal==EXTCLK_33_33)
545 && (extClkVal==EXTCLK_50)
546 && (extClkVal==EXTCLK_66_66)
547 && (extClkVal==EXTCLK_83)) {
548 /* calculate master clock period from external clock value */
549 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
552 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
558 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
563 /* Determine FB divisors values */
564 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
565 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
566 fb_div_selection = FPGA_FB_DIV_6;
568 fb_div_selection = FPGA_FB_DIV_12;
570 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
571 fb_div_selection = FPGA_FB_DIV_10;
573 fb_div_selection = FPGA_FB_DIV_20;
576 /* Determine VCO divisors values */
577 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
579 switch(vco_div_reg_value) {
580 case FPGA_REG16_VCO_DIV_4:
581 vco_div_selection = FPGA_VCO_DIV_4;
583 case FPGA_REG16_VCO_DIV_6:
584 vco_div_selection = FPGA_VCO_DIV_6;
586 case FPGA_REG16_VCO_DIV_8:
587 vco_div_selection = FPGA_VCO_DIV_8;
589 case FPGA_REG16_VCO_DIV_10:
591 vco_div_selection = FPGA_VCO_DIV_10;
595 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
596 switch(master_clock_per) {
597 case PERIOD_25_00MHZ:
598 if (fb_div_selection == FPGA_FB_DIV_12) {
599 if (vco_div_selection == FPGA_VCO_DIV_4)
600 sys_per = PERIOD_75_00MHZ;
601 if (vco_div_selection == FPGA_VCO_DIV_6)
602 sys_per = PERIOD_50_00MHZ;
605 case PERIOD_33_33MHZ:
606 if (fb_div_selection == FPGA_FB_DIV_6) {
607 if (vco_div_selection == FPGA_VCO_DIV_4)
608 sys_per = PERIOD_50_00MHZ;
609 if (vco_div_selection == FPGA_VCO_DIV_6)
610 sys_per = PERIOD_33_33MHZ;
612 if (fb_div_selection == FPGA_FB_DIV_10) {
613 if (vco_div_selection == FPGA_VCO_DIV_4)
614 sys_per = PERIOD_83_33MHZ;
615 if (vco_div_selection == FPGA_VCO_DIV_10)
616 sys_per = PERIOD_33_33MHZ;
618 if (fb_div_selection == FPGA_FB_DIV_12) {
619 if (vco_div_selection == FPGA_VCO_DIV_4)
620 sys_per = PERIOD_100_00MHZ;
621 if (vco_div_selection == FPGA_VCO_DIV_6)
622 sys_per = PERIOD_66_66MHZ;
623 if (vco_div_selection == FPGA_VCO_DIV_8)
624 sys_per = PERIOD_50_00MHZ;
627 case PERIOD_50_00MHZ:
628 if (fb_div_selection == FPGA_FB_DIV_6) {
629 if (vco_div_selection == FPGA_VCO_DIV_4)
630 sys_per = PERIOD_75_00MHZ;
631 if (vco_div_selection == FPGA_VCO_DIV_6)
632 sys_per = PERIOD_50_00MHZ;
634 if (fb_div_selection == FPGA_FB_DIV_10) {
635 if (vco_div_selection == FPGA_VCO_DIV_6)
636 sys_per = PERIOD_83_33MHZ;
637 if (vco_div_selection == FPGA_VCO_DIV_10)
638 sys_per = PERIOD_50_00MHZ;
640 if (fb_div_selection == FPGA_FB_DIV_12) {
641 if (vco_div_selection == FPGA_VCO_DIV_6)
642 sys_per = PERIOD_100_00MHZ;
643 if (vco_div_selection == FPGA_VCO_DIV_8)
644 sys_per = PERIOD_75_00MHZ;
647 case PERIOD_66_66MHZ:
648 if (fb_div_selection == FPGA_FB_DIV_6) {
649 if (vco_div_selection == FPGA_VCO_DIV_4)
650 sys_per = PERIOD_100_00MHZ;
651 if (vco_div_selection == FPGA_VCO_DIV_6)
652 sys_per = PERIOD_66_66MHZ;
653 if (vco_div_selection == FPGA_VCO_DIV_8)
654 sys_per = PERIOD_50_00MHZ;
656 if (fb_div_selection == FPGA_FB_DIV_10) {
657 if (vco_div_selection == FPGA_VCO_DIV_8)
658 sys_per = PERIOD_83_33MHZ;
659 if (vco_div_selection == FPGA_VCO_DIV_10)
660 sys_per = PERIOD_66_66MHZ;
662 if (fb_div_selection == FPGA_FB_DIV_12) {
663 if (vco_div_selection == FPGA_VCO_DIV_8)
664 sys_per = PERIOD_100_00MHZ;
672 /* Other combinations are not supported */
673 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
677 /* calcul system clock without cheking */
678 /* if engineering option clock no check is selected */
679 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
680 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
686 /*-------------------------------------------------------------------------+
687 | determine_pci_clock_per.
688 +-------------------------------------------------------------------------*/
689 unsigned long determine_pci_clock_per(void)
691 unsigned long pci_clock_selection, pci_period;
693 /*-------------------------------------------------------------------------+
694 | Read FPGA reg 6 to get PCI 0 FPGA reg information
695 +-------------------------------------------------------------------------*/
696 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
699 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
701 switch (pci_clock_selection) {
702 case FPGA_REG16_PCI0_CLK_133_33:
703 pci_period = PERIOD_133_33MHZ;
705 case FPGA_REG16_PCI0_CLK_100:
706 pci_period = PERIOD_100_00MHZ;
708 case FPGA_REG16_PCI0_CLK_66_66:
709 pci_period = PERIOD_66_66MHZ;
712 pci_period = PERIOD_33_33MHZ;;
720 #elif defined(CONFIG_XILINX_405)
721 extern void get_sys_info (sys_info_t * sysInfo);
722 extern ulong get_PCI_freq (void);
724 #elif defined(CONFIG_405)
726 void get_sys_info (sys_info_t * sysInfo)
728 sysInfo->freqVCOMhz=3125000;
729 sysInfo->freqProcessor=12*1000*1000;
730 sysInfo->freqPLB=50*1000*1000;
731 sysInfo->freqPCI=66*1000*1000;
734 #elif defined(CONFIG_405EP)
735 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
737 unsigned long pllmr0;
738 unsigned long pllmr1;
739 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
741 unsigned long pllmr0_ccdv;
744 * Read PLL Mode registers
746 pllmr0 = mfdcr (CPC0_PLLMR0);
747 pllmr1 = mfdcr (CPC0_PLLMR1);
750 * Determine forward divider A
752 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
755 * Determine forward divider B (should be equal to A)
757 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
762 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
763 if (sysInfo->pllFbkDiv == 0)
764 sysInfo->pllFbkDiv = 16;
769 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
774 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
777 * Determine EXTBUS_DIV.
779 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
784 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
787 * Determine the M factor
789 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
792 * Determine VCO clock frequency
794 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
795 (unsigned long long)sysClkPeriodPs;
798 * Determine CPU clock frequency
800 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
801 if (pllmr1 & PLLMR1_SSCS_MASK) {
803 * This is true if FWDVA == FWDVB:
804 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
807 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
808 / sysInfo->pllFwdDiv / pllmr0_ccdv;
810 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
814 * Determine PLB clock frequency
816 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
818 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
820 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
822 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
826 /********************************************
828 * return PCI bus freq in Hz
829 *********************************************/
830 ulong get_PCI_freq (void)
833 PPC4xx_SYS_INFO sys_info;
835 get_sys_info (&sys_info);
836 val = sys_info.freqPLB / sys_info.pllPciDiv;
840 #elif defined(CONFIG_405EZ)
841 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
843 unsigned long cpr_plld;
844 unsigned long cpr_pllc;
845 unsigned long cpr_primad;
846 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
847 unsigned long primad_cpudv;
849 unsigned long plloutb;
852 * Read PLL Mode registers
854 mfcpr(CPR0_PLLD, cpr_plld);
855 mfcpr(CPR0_PLLC, cpr_pllc);
858 * Determine forward divider A
860 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
863 * Determine forward divider B
865 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
866 if (sysInfo->pllFwdDivB == 0)
867 sysInfo->pllFwdDivB = 8;
872 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
873 if (sysInfo->pllFbkDiv == 0)
874 sysInfo->pllFbkDiv = 256;
877 * Read CPR_PRIMAD register
879 mfcpr(CPR0_PRIMAD, cpr_primad);
884 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
885 if (sysInfo->pllPlbDiv == 0)
886 sysInfo->pllPlbDiv = 16;
889 * Determine EXTBUS_DIV.
891 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
892 if (sysInfo->pllExtBusDiv == 0)
893 sysInfo->pllExtBusDiv = 16;
898 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
899 if (sysInfo->pllOpbDiv == 0)
900 sysInfo->pllOpbDiv = 16;
903 * Determine the M factor
905 if (cpr_pllc & PLLC_SRC_MASK)
906 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
908 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
911 * Determine VCO clock frequency
913 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
914 (unsigned long long)sysClkPeriodPs;
917 * Determine CPU clock frequency
919 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
920 if (primad_cpudv == 0)
923 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
924 sysInfo->pllFwdDiv / primad_cpudv;
927 * Determine PLB clock frequency
929 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
930 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
932 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
935 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
936 sysInfo->pllExtBusDiv;
938 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
939 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
940 sysInfo->pllFwdDivB);
941 sysInfo->freqUART = plloutb;
944 #elif defined(CONFIG_405EX)
947 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
948 * We need the specs!!!!
950 static unsigned char get_fbdv(unsigned char index)
952 unsigned char ret = 0;
953 /* This is table should be 256 bytes.
954 * Only take first 52 values.
956 unsigned char fbdv_tb[] = {
957 0x00, 0xff, 0x7f, 0xfd,
958 0x7a, 0xf5, 0x6a, 0xd5,
959 0x2a, 0xd4, 0x29, 0xd3,
960 0x26, 0xcc, 0x19, 0xb3,
961 0x67, 0xce, 0x1d, 0xbb,
962 0x77, 0xee, 0x5d, 0xba,
963 0x74, 0xe9, 0x52, 0xa5,
964 0x4b, 0x96, 0x2c, 0xd8,
965 0x31, 0xe3, 0x46, 0x8d,
966 0x1b, 0xb7, 0x6f, 0xde,
967 0x3d, 0xfb, 0x76, 0xed,
968 0x5a, 0xb5, 0x6b, 0xd6,
969 0x2d, 0xdb, 0x36, 0xec,
973 if ((index & 0x7f) == 0)
975 while (ret < sizeof (fbdv_tb)) {
976 if (fbdv_tb[ret] == index)
985 #define PLL_FBK_PLL_LOCAL 0
986 #define PLL_FBK_CPU 1
987 #define PLL_FBK_PERCLK 5
989 void get_sys_info (sys_info_t * sysInfo)
991 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
994 unsigned char fwdva[16] = {
995 1, 2, 14, 9, 4, 11, 16, 13,
996 12, 5, 6, 15, 10, 7, 8, 3,
998 unsigned char sel, cpudv0, plb2xDiv;
1000 mfcpr(CPR0_PLLD, tmp);
1003 * Determine forward divider A
1005 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1008 * Determine FBK_DIV.
1010 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1015 sysInfo->pllPlbDiv = 2;
1020 mfcpr(CPR0_PERD, tmp);
1021 tmp = (tmp >> 24) & 0x03;
1022 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1027 mfcpr(CPR0_OPBD0, tmp);
1028 tmp = (tmp >> 24) & 0x03;
1029 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1031 /* Determine PLB2XDV0 */
1032 mfcpr(CPR0_PLBD, tmp);
1033 tmp = (tmp >> 16) & 0x07;
1034 plb2xDiv = (tmp == 0) ? 8 : tmp;
1036 /* Determine CPUDV0 */
1037 mfcpr(CPR0_CPUD, tmp);
1038 tmp = (tmp >> 24) & 0x07;
1039 cpudv0 = (tmp == 0) ? 8 : tmp;
1041 /* Determine SEL(5:7) in CPR0_PLLC */
1042 mfcpr(CPR0_PLLC, tmp);
1043 sel = (tmp >> 24) & 0x07;
1046 * Determine the M factor
1047 * PLL local: M = FBDV
1048 * CPU clock: M = FBDV * FWDVA * CPUDV0
1049 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1054 m = sysInfo->pllFwdDiv * cpudv0;
1056 case PLL_FBK_PERCLK:
1057 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1058 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1060 case PLL_FBK_PLL_LOCAL:
1063 printf("%s unknown m\n", __FUNCTION__);
1067 m *= sysInfo->pllFbkDiv;
1070 * Determine VCO clock frequency
1072 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1073 (unsigned long long)sysClkPeriodPs;
1076 * Determine CPU clock frequency
1078 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1081 * Determine PLB clock frequency, ddr1x should be the same
1083 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1084 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1085 sysInfo->freqDDR = sysInfo->freqPLB;
1086 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1087 sysInfo->freqUART = sysInfo->freqPLB;
1092 int get_clocks (void)
1094 sys_info_t sys_info;
1096 get_sys_info (&sys_info);
1097 gd->cpu_clk = sys_info.freqProcessor;
1098 gd->bus_clk = sys_info.freqPLB;
1104 /********************************************
1106 * return PLB bus freq in Hz
1107 *********************************************/
1108 ulong get_bus_freq (ulong dummy)
1112 #if defined(CONFIG_405GP) || \
1113 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1114 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1116 sys_info_t sys_info;
1118 get_sys_info (&sys_info);
1119 val = sys_info.freqPLB;
1121 # error get_bus_freq() not implemented
1127 ulong get_OPB_freq (void)
1129 PPC4xx_SYS_INFO sys_info;
1131 get_sys_info (&sys_info);
1133 return sys_info.freqOPB;