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>
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)
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])
254
* AMCC_TODO: verify this routine against latest EAS, cause stuff changed
257
void get_sys_info (sys_info_t * sysInfo)
263
unsigned long plbedv0;
265
/* Extract configured divisors */
266
mfsdr(SDR0_SDSTP0, strp0);
267
mfsdr(SDR0_SDSTP1, strp1);
269
temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
270
sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
272
temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
273
sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
275
temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
276
sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
278
temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
279
sysInfo->pllOpbDiv = temp ? temp : 4;
281
/* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
282
temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
283
sysInfo->pllExtBusDiv = temp ? temp : 4;
285
temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
286
plbedv0 = temp ? temp: 8;
288
/* Calculate 'M' based on feedback source */
289
temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
291
/* PLL internal feedback */
292
m = sysInfo->pllFbkDiv;
294
/* PLL PerClk feedback */
295
m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
296
sysInfo->pllExtBusDiv;
299
/* Now calculate the individual clocks */
300
sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
301
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
302
sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
303
sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
304
sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
305
sysInfo->freqDDR = sysInfo->freqPLB;
306
sysInfo->freqUART = sysInfo->freqPLB;
311
#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
312
defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
313
void get_sys_info (sys_info_t *sysInfo)
319
unsigned long prbdv0;
321
WARNING: ASSUMES the following:
327
/* Decode CPR0_PLLD0 for divisors */
328
mfcpr(CPR0_PLLD, reg);
329
temp = (reg & PLLD_FWDVA_MASK) >> 16;
330
sysInfo->pllFwdDivA = temp ? temp : 16;
331
temp = (reg & PLLD_FWDVB_MASK) >> 8;
332
sysInfo->pllFwdDivB = temp ? temp: 8 ;
333
temp = (reg & PLLD_FBDV_MASK) >> 24;
334
sysInfo->pllFbkDiv = temp ? temp : 32;
335
lfdiv = reg & PLLD_LFBDV_MASK;
337
mfcpr(CPR0_OPBD0, reg);
338
temp = (reg & OPBDDV_MASK) >> 24;
339
sysInfo->pllOpbDiv = temp ? temp : 4;
341
mfcpr(CPR0_PERD, reg);
342
temp = (reg & PERDV_MASK) >> 24;
343
sysInfo->pllExtBusDiv = temp ? temp : 8;
345
mfcpr(CPR0_PRIMBD0, reg);
346
temp = (reg & PRBDV_MASK) >> 24;
347
prbdv0 = temp ? temp : 8;
349
mfcpr(CPR0_SPCID, reg);
350
temp = (reg & SPCID_MASK) >> 24;
351
sysInfo->pllPciDiv = temp ? temp : 4;
353
/* Calculate 'M' based on feedback source */
354
mfsdr(SDR0_SDSTP0, reg);
355
temp = (reg & PLLSYS0_SEL_MASK) >> 27;
356
if (temp == 0) { /* PLL output */
357
/* Figure which pll to use */
358
mfcpr(CPR0_PLLC, reg);
359
temp = (reg & PLLC_SRC_MASK) >> 29;
360
if (!temp) /* PLLOUTA */
361
m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
363
m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
365
else if (temp == 1) /* CPU output */
366
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
368
m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
370
/* Now calculate the individual clocks */
371
sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
372
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
373
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
374
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
375
sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
376
sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
377
sysInfo->freqUART = sysInfo->freqPLB;
379
/* Figure which timer source to use */
380
if (mfspr(SPRN_CCR1) & 0x0080) {
381
/* External Clock, assume same as SYS_CLK */
382
temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
383
if (CONFIG_SYS_CLK_FREQ > temp)
384
sysInfo->freqTmrClk = temp;
386
sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
388
else /* Internal clock */
389
sysInfo->freqTmrClk = sysInfo->freqProcessor;
392
/********************************************
394
* return PCI bus freq in Hz
395
*********************************************/
396
ulong get_PCI_freq (void)
399
get_sys_info (&sys_info);
400
return sys_info.freqPCI;
403
#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
404
&& !defined(CONFIG_XILINX_440)
405
void get_sys_info (sys_info_t * sysInfo)
411
/* Extract configured divisors */
412
strp0 = mfdcr( CPC0_STRP0 );
413
sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
414
sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
415
temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
416
sysInfo->pllFbkDiv = temp ? temp : 16;
417
sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
418
sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
420
/* Calculate 'M' based on feedback source */
421
if( strp0 & PLLSYS0_EXTSL_MASK )
422
m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
424
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
426
/* Now calculate the individual clocks */
427
sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
428
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
429
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
430
if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
431
sysInfo->freqPLB >>= 1;
432
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
433
sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
434
sysInfo->freqUART = sysInfo->freqPLB;
438
#if !defined(CONFIG_XILINX_440)
439
void get_sys_info (sys_info_t * sysInfo)
447
unsigned long prbdv0;
449
#if defined(CONFIG_YUCCA)
450
unsigned long sys_freq;
451
unsigned long sys_per=0;
453
unsigned long pci_clock_per;
454
unsigned long sdr_ddrpll;
456
/*-------------------------------------------------------------------------+
457
| Get the system clock period.
458
+-------------------------------------------------------------------------*/
459
sys_per = determine_sysper();
461
msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
463
/*-------------------------------------------------------------------------+
464
| Calculate the system clock speed from the period.
465
+-------------------------------------------------------------------------*/
466
sys_freq = (ONE_BILLION / sys_per) * 1000;
469
/* Extract configured divisors */
470
mfsdr( SDR0_SDSTP0,strp0 );
471
mfsdr( SDR0_SDSTP1,strp1 );
473
temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
474
sysInfo->pllFwdDivA = temp ? temp : 16 ;
475
temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
476
sysInfo->pllFwdDivB = temp ? temp: 8 ;
477
temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
478
sysInfo->pllFbkDiv = temp ? temp : 32;
479
temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
480
sysInfo->pllOpbDiv = temp ? temp : 4;
481
temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
482
sysInfo->pllExtBusDiv = temp ? temp : 4;
483
prbdv0 = (strp0 >> 2) & 0x7;
485
/* Calculate 'M' based on feedback source */
486
temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
487
temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
488
lfdiv = temp1 ? temp1 : 64;
489
if (temp == 0) { /* PLL output */
490
/* Figure which pll to use */
491
temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
493
m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
495
m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
497
else if (temp == 1) /* CPU output */
498
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
500
m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
502
/* Now calculate the individual clocks */
503
#if defined(CONFIG_YUCCA)
504
sysInfo->freqVCOMhz = (m * sys_freq) ;
506
sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
508
sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
509
sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
510
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
511
sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
513
#if defined(CONFIG_YUCCA)
514
/* Determine PCI Clock Period */
515
pci_clock_per = determine_pci_clock_per();
516
sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
517
mfsdr(SDR0_DDR0, sdr_ddrpll);
518
sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
521
sysInfo->freqUART = sysInfo->freqPLB;
525
#endif /* CONFIG_XILINX_440 */
527
#if defined(CONFIG_YUCCA)
528
unsigned long determine_sysper(void)
530
unsigned int fpga_clocking_reg;
531
unsigned int master_clock_selection;
532
unsigned long master_clock_per = 0;
533
unsigned long fb_div_selection;
534
unsigned int vco_div_reg_value;
535
unsigned long vco_div_selection;
536
unsigned long sys_per = 0;
539
/*-------------------------------------------------------------------------+
540
| Read FPGA reg 0 and reg 1 to get FPGA reg information
541
+-------------------------------------------------------------------------*/
542
fpga_clocking_reg = in16(FPGA_REG16);
545
/* Determine Master Clock Source Selection */
546
master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
548
switch(master_clock_selection) {
549
case FPGA_REG16_MASTER_CLK_66_66:
550
master_clock_per = PERIOD_66_66MHZ;
552
case FPGA_REG16_MASTER_CLK_50:
553
master_clock_per = PERIOD_50_00MHZ;
555
case FPGA_REG16_MASTER_CLK_33_33:
556
master_clock_per = PERIOD_33_33MHZ;
558
case FPGA_REG16_MASTER_CLK_25:
559
master_clock_per = PERIOD_25_00MHZ;
561
case FPGA_REG16_MASTER_CLK_EXT:
562
if ((extClkVal==EXTCLK_33_33)
563
&& (extClkVal==EXTCLK_50)
564
&& (extClkVal==EXTCLK_66_66)
565
&& (extClkVal==EXTCLK_83)) {
566
/* calculate master clock period from external clock value */
567
master_clock_per=(ONE_BILLION/extClkVal) * 1000;
570
DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
576
DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
581
/* Determine FB divisors values */
582
if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
583
if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
584
fb_div_selection = FPGA_FB_DIV_6;
586
fb_div_selection = FPGA_FB_DIV_12;
588
if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
589
fb_div_selection = FPGA_FB_DIV_10;
591
fb_div_selection = FPGA_FB_DIV_20;
594
/* Determine VCO divisors values */
595
vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
597
switch(vco_div_reg_value) {
598
case FPGA_REG16_VCO_DIV_4:
599
vco_div_selection = FPGA_VCO_DIV_4;
601
case FPGA_REG16_VCO_DIV_6:
602
vco_div_selection = FPGA_VCO_DIV_6;
604
case FPGA_REG16_VCO_DIV_8:
605
vco_div_selection = FPGA_VCO_DIV_8;
607
case FPGA_REG16_VCO_DIV_10:
609
vco_div_selection = FPGA_VCO_DIV_10;
613
if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
614
switch(master_clock_per) {
615
case PERIOD_25_00MHZ:
616
if (fb_div_selection == FPGA_FB_DIV_12) {
617
if (vco_div_selection == FPGA_VCO_DIV_4)
618
sys_per = PERIOD_75_00MHZ;
619
if (vco_div_selection == FPGA_VCO_DIV_6)
620
sys_per = PERIOD_50_00MHZ;
623
case PERIOD_33_33MHZ:
624
if (fb_div_selection == FPGA_FB_DIV_6) {
625
if (vco_div_selection == FPGA_VCO_DIV_4)
626
sys_per = PERIOD_50_00MHZ;
627
if (vco_div_selection == FPGA_VCO_DIV_6)
628
sys_per = PERIOD_33_33MHZ;
630
if (fb_div_selection == FPGA_FB_DIV_10) {
631
if (vco_div_selection == FPGA_VCO_DIV_4)
632
sys_per = PERIOD_83_33MHZ;
633
if (vco_div_selection == FPGA_VCO_DIV_10)
634
sys_per = PERIOD_33_33MHZ;
636
if (fb_div_selection == FPGA_FB_DIV_12) {
637
if (vco_div_selection == FPGA_VCO_DIV_4)
638
sys_per = PERIOD_100_00MHZ;
639
if (vco_div_selection == FPGA_VCO_DIV_6)
640
sys_per = PERIOD_66_66MHZ;
641
if (vco_div_selection == FPGA_VCO_DIV_8)
642
sys_per = PERIOD_50_00MHZ;
645
case PERIOD_50_00MHZ:
646
if (fb_div_selection == FPGA_FB_DIV_6) {
647
if (vco_div_selection == FPGA_VCO_DIV_4)
648
sys_per = PERIOD_75_00MHZ;
649
if (vco_div_selection == FPGA_VCO_DIV_6)
650
sys_per = PERIOD_50_00MHZ;
652
if (fb_div_selection == FPGA_FB_DIV_10) {
653
if (vco_div_selection == FPGA_VCO_DIV_6)
654
sys_per = PERIOD_83_33MHZ;
655
if (vco_div_selection == FPGA_VCO_DIV_10)
656
sys_per = PERIOD_50_00MHZ;
658
if (fb_div_selection == FPGA_FB_DIV_12) {
659
if (vco_div_selection == FPGA_VCO_DIV_6)
660
sys_per = PERIOD_100_00MHZ;
661
if (vco_div_selection == FPGA_VCO_DIV_8)
662
sys_per = PERIOD_75_00MHZ;
665
case PERIOD_66_66MHZ:
666
if (fb_div_selection == FPGA_FB_DIV_6) {
667
if (vco_div_selection == FPGA_VCO_DIV_4)
668
sys_per = PERIOD_100_00MHZ;
669
if (vco_div_selection == FPGA_VCO_DIV_6)
670
sys_per = PERIOD_66_66MHZ;
671
if (vco_div_selection == FPGA_VCO_DIV_8)
672
sys_per = PERIOD_50_00MHZ;
674
if (fb_div_selection == FPGA_FB_DIV_10) {
675
if (vco_div_selection == FPGA_VCO_DIV_8)
676
sys_per = PERIOD_83_33MHZ;
677
if (vco_div_selection == FPGA_VCO_DIV_10)
678
sys_per = PERIOD_66_66MHZ;
680
if (fb_div_selection == FPGA_FB_DIV_12) {
681
if (vco_div_selection == FPGA_VCO_DIV_8)
682
sys_per = PERIOD_100_00MHZ;
690
/* Other combinations are not supported */
691
DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
695
/* calcul system clock without cheking */
696
/* if engineering option clock no check is selected */
697
/* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
698
sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
704
/*-------------------------------------------------------------------------+
705
| determine_pci_clock_per.
706
+-------------------------------------------------------------------------*/
707
unsigned long determine_pci_clock_per(void)
709
unsigned long pci_clock_selection, pci_period;
711
/*-------------------------------------------------------------------------+
712
| Read FPGA reg 6 to get PCI 0 FPGA reg information
713
+-------------------------------------------------------------------------*/
714
pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
717
pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
719
switch (pci_clock_selection) {
720
case FPGA_REG16_PCI0_CLK_133_33:
721
pci_period = PERIOD_133_33MHZ;
723
case FPGA_REG16_PCI0_CLK_100:
724
pci_period = PERIOD_100_00MHZ;
726
case FPGA_REG16_PCI0_CLK_66_66:
727
pci_period = PERIOD_66_66MHZ;
730
pci_period = PERIOD_33_33MHZ;;
738
#elif defined(CONFIG_XILINX_405)
739
extern void get_sys_info (sys_info_t * sysInfo);
740
extern ulong get_PCI_freq (void);
742
#elif defined(CONFIG_AP1000)
743
void get_sys_info (sys_info_t * sysInfo)
745
sysInfo->freqProcessor = 240 * 1000 * 1000;
746
sysInfo->freqPLB = 80 * 1000 * 1000;
747
sysInfo->freqPCI = 33 * 1000 * 1000;
750
#elif defined(CONFIG_405)
752
void get_sys_info (sys_info_t * sysInfo)
754
sysInfo->freqVCOMhz=3125000;
755
sysInfo->freqProcessor=12*1000*1000;
756
sysInfo->freqPLB=50*1000*1000;
757
sysInfo->freqPCI=66*1000*1000;
760
#elif defined(CONFIG_405EP)
761
void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
763
unsigned long pllmr0;
764
unsigned long pllmr1;
765
unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
767
unsigned long pllmr0_ccdv;
770
* Read PLL Mode registers
772
pllmr0 = mfdcr (CPC0_PLLMR0);
773
pllmr1 = mfdcr (CPC0_PLLMR1);
776
* Determine forward divider A
778
sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
781
* Determine forward divider B (should be equal to A)
783
sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
788
sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
789
if (sysInfo->pllFbkDiv == 0)
790
sysInfo->pllFbkDiv = 16;
795
sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
800
sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
803
* Determine EXTBUS_DIV.
805
sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
810
sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
813
* Determine the M factor
815
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
818
* Determine VCO clock frequency
820
sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
821
(unsigned long long)sysClkPeriodPs;
824
* Determine CPU clock frequency
826
pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
827
if (pllmr1 & PLLMR1_SSCS_MASK) {
829
* This is true if FWDVA == FWDVB:
830
* sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
833
sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
834
/ sysInfo->pllFwdDiv / pllmr0_ccdv;
836
sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
840
* Determine PLB clock frequency
842
sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
844
sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
846
sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
848
sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
852
/********************************************
854
* return PCI bus freq in Hz
855
*********************************************/
856
ulong get_PCI_freq (void)
859
PPC4xx_SYS_INFO sys_info;
861
get_sys_info (&sys_info);
862
val = sys_info.freqPLB / sys_info.pllPciDiv;
866
#elif defined(CONFIG_405EZ)
867
void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
869
unsigned long cpr_plld;
870
unsigned long cpr_pllc;
871
unsigned long cpr_primad;
872
unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
873
unsigned long primad_cpudv;
875
unsigned long plloutb;
878
* Read PLL Mode registers
880
mfcpr(CPR0_PLLD, cpr_plld);
881
mfcpr(CPR0_PLLC, cpr_pllc);
884
* Determine forward divider A
886
sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
889
* Determine forward divider B
891
sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
892
if (sysInfo->pllFwdDivB == 0)
893
sysInfo->pllFwdDivB = 8;
898
sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
899
if (sysInfo->pllFbkDiv == 0)
900
sysInfo->pllFbkDiv = 256;
903
* Read CPR_PRIMAD register
905
mfcpr(CPC0_PRIMAD, cpr_primad);
910
sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
911
if (sysInfo->pllPlbDiv == 0)
912
sysInfo->pllPlbDiv = 16;
915
* Determine EXTBUS_DIV.
917
sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
918
if (sysInfo->pllExtBusDiv == 0)
919
sysInfo->pllExtBusDiv = 16;
924
sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
925
if (sysInfo->pllOpbDiv == 0)
926
sysInfo->pllOpbDiv = 16;
929
* Determine the M factor
931
if (cpr_pllc & PLLC_SRC_MASK)
932
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
934
m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
937
* Determine VCO clock frequency
939
sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
940
(unsigned long long)sysClkPeriodPs;
943
* Determine CPU clock frequency
945
primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
946
if (primad_cpudv == 0)
949
sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
950
sysInfo->pllFwdDiv / primad_cpudv;
953
* Determine PLB clock frequency
955
sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
956
sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
958
sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
961
sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
962
sysInfo->pllExtBusDiv;
964
plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
965
sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
966
sysInfo->pllFwdDivB);
967
sysInfo->freqUART = plloutb;
970
#elif defined(CONFIG_405EX)
973
* TODO: We need to get the CPR registers and calculate these values correctly!!!!
974
* We need the specs!!!!
976
static unsigned char get_fbdv(unsigned char index)
978
unsigned char ret = 0;
979
/* This is table should be 256 bytes.
980
* Only take first 52 values.
982
unsigned char fbdv_tb[] = {
983
0x00, 0xff, 0x7f, 0xfd,
984
0x7a, 0xf5, 0x6a, 0xd5,
985
0x2a, 0xd4, 0x29, 0xd3,
986
0x26, 0xcc, 0x19, 0xb3,
987
0x67, 0xce, 0x1d, 0xbb,
988
0x77, 0xee, 0x5d, 0xba,
989
0x74, 0xe9, 0x52, 0xa5,
990
0x4b, 0x96, 0x2c, 0xd8,
991
0x31, 0xe3, 0x46, 0x8d,
992
0x1b, 0xb7, 0x6f, 0xde,
993
0x3d, 0xfb, 0x76, 0xed,
994
0x5a, 0xb5, 0x6b, 0xd6,
995
0x2d, 0xdb, 0x36, 0xec,
999
if ((index & 0x7f) == 0)
1001
while (ret < sizeof (fbdv_tb)) {
1002
if (fbdv_tb[ret] == index)
1011
#define PLL_FBK_PLL_LOCAL 0
1012
#define PLL_FBK_CPU 1
1013
#define PLL_FBK_PERCLK 5
1015
void get_sys_info (sys_info_t * sysInfo)
1017
unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1018
unsigned long m = 1;
1020
unsigned char fwdva[16] = {
1021
1, 2, 14, 9, 4, 11, 16, 13,
1022
12, 5, 6, 15, 10, 7, 8, 3,
1024
unsigned char sel, cpudv0, plb2xDiv;
1026
mfcpr(CPR0_PLLD, tmp);
1029
* Determine forward divider A
1031
sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1034
* Determine FBK_DIV.
1036
sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1041
sysInfo->pllPlbDiv = 2;
1046
mfcpr(CPR0_PERD, tmp);
1047
tmp = (tmp >> 24) & 0x03;
1048
sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1053
mfcpr(CPR0_OPBD0, tmp);
1054
tmp = (tmp >> 24) & 0x03;
1055
sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1057
/* Determine PLB2XDV0 */
1058
mfcpr(CPR0_PLBD, tmp);
1059
tmp = (tmp >> 16) & 0x07;
1060
plb2xDiv = (tmp == 0) ? 8 : tmp;
1062
/* Determine CPUDV0 */
1063
mfcpr(CPR0_CPUD, tmp);
1064
tmp = (tmp >> 24) & 0x07;
1065
cpudv0 = (tmp == 0) ? 8 : tmp;
1067
/* Determine SEL(5:7) in CPR0_PLLC */
1068
mfcpr(CPR0_PLLC, tmp);
1069
sel = (tmp >> 24) & 0x07;
1072
* Determine the M factor
1073
* PLL local: M = FBDV
1074
* CPU clock: M = FBDV * FWDVA * CPUDV0
1075
* PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1080
m = sysInfo->pllFwdDiv * cpudv0;
1082
case PLL_FBK_PERCLK:
1083
m = sysInfo->pllFwdDiv * plb2xDiv * 2
1084
* sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1086
case PLL_FBK_PLL_LOCAL:
1089
printf("%s unknown m\n", __FUNCTION__);
1093
m *= sysInfo->pllFbkDiv;
1096
* Determine VCO clock frequency
1098
sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1099
(unsigned long long)sysClkPeriodPs;
1102
* Determine CPU clock frequency
1104
sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1107
* Determine PLB clock frequency, ddr1x should be the same
1109
sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1110
sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1111
sysInfo->freqDDR = sysInfo->freqPLB;
1112
sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1113
sysInfo->freqUART = sysInfo->freqPLB;
1118
int get_clocks (void)
1120
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1121
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1122
defined(CONFIG_405EX) || defined(CONFIG_405) || \
1124
sys_info_t sys_info;
1126
get_sys_info (&sys_info);
1127
gd->cpu_clk = sys_info.freqProcessor;
1128
gd->bus_clk = sys_info.freqPLB;
1130
#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1132
#ifdef CONFIG_IOP480
1133
gd->cpu_clk = 66000000;
1134
gd->bus_clk = 66000000;
1140
/********************************************
1142
* return PLB bus freq in Hz
1143
*********************************************/
1144
ulong get_bus_freq (ulong dummy)
1148
#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1149
defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1150
defined(CONFIG_405EX) || defined(CONFIG_405) || \
1152
sys_info_t sys_info;
1154
get_sys_info (&sys_info);
1155
val = sys_info.freqPLB;
1157
#elif defined(CONFIG_IOP480)
1162
# error get_bus_freq() not implemented
1168
#if !defined(CONFIG_IOP480)
1169
ulong get_OPB_freq (void)
1171
PPC4xx_SYS_INFO sys_info;
1173
get_sys_info (&sys_info);
1175
return sys_info.freqOPB;