]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/powerpc/cpu/ppc4xx/speed.c
blackfin, powerpc: remove redundant definitions of ARRAY_SIZE
[people/ms/u-boot.git] / arch / powerpc / cpu / ppc4xx / speed.c
1 /*
2 * (C) Copyright 2000-2008
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * SPDX-License-Identifier: GPL-2.0+
6 */
7
8 #include <common.h>
9 #include <ppc_asm.tmpl>
10 #include <asm/ppc4xx.h>
11 #include <asm/processor.h>
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 #define ONE_BILLION 1000000000
16 #ifdef DEBUG
17 #define DEBUGF(fmt,args...) printf(fmt ,##args)
18 #else
19 #define DEBUGF(fmt,args...)
20 #endif
21
22 #if defined(CONFIG_405GP)
23
24 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
25 {
26 unsigned long pllmr;
27 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
28 uint pvr = get_pvr();
29 unsigned long psr;
30 unsigned long m;
31
32 /*
33 * Read PLL Mode register
34 */
35 pllmr = mfdcr (CPC0_PLLMR);
36
37 /*
38 * Read Pin Strapping register
39 */
40 psr = mfdcr (CPC0_PSR);
41
42 /*
43 * Determine FWD_DIV.
44 */
45 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
46
47 /*
48 * Determine FBK_DIV.
49 */
50 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
51 if (sysInfo->pllFbkDiv == 0) {
52 sysInfo->pllFbkDiv = 16;
53 }
54
55 /*
56 * Determine PLB_DIV.
57 */
58 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
59
60 /*
61 * Determine PCI_DIV.
62 */
63 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
64
65 /*
66 * Determine EXTBUS_DIV.
67 */
68 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
69
70 /*
71 * Determine OPB_DIV.
72 */
73 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
74
75 /*
76 * Check if PPC405GPr used (mask minor revision field)
77 */
78 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
79 /*
80 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
81 */
82 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
83
84 /*
85 * Determine factor m depending on PLL feedback clock source
86 */
87 if (!(psr & PSR_PCI_ASYNC_EN)) {
88 if (psr & PSR_NEW_MODE_EN) {
89 /*
90 * sync pci clock used as feedback (new mode)
91 */
92 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
93 } else {
94 /*
95 * sync pci clock used as feedback (legacy mode)
96 */
97 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
98 }
99 } else if (psr & PSR_NEW_MODE_EN) {
100 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
101 /*
102 * PerClk used as feedback (new mode)
103 */
104 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
105 } else {
106 /*
107 * CPU clock used as feedback (new mode)
108 */
109 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
110 }
111 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
112 /*
113 * PerClk used as feedback (legacy mode)
114 */
115 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
116 } else {
117 /*
118 * PLB clock used as feedback (legacy mode)
119 */
120 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
121 }
122
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);
127 } else {
128 /*
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.
134 */
135 if (sysInfo->pllFwdDiv == 1) {
136 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
137 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
138 } else {
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;
147 }
148 }
149
150 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
151 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
152 sysInfo->freqUART = sysInfo->freqProcessor;
153 }
154
155
156 /********************************************
157 * get_PCI_freq
158 * return PCI bus freq in Hz
159 *********************************************/
160 ulong get_PCI_freq (void)
161 {
162 ulong val;
163 PPC4xx_SYS_INFO sys_info;
164
165 get_sys_info (&sys_info);
166 val = sys_info.freqPLB / sys_info.pllPciDiv;
167 return val;
168 }
169
170
171 #elif defined(CONFIG_440)
172
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
179 };
180
181 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
182 {
183 u32 index;
184
185 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
186 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
187 return index + 1;
188
189 return 0;
190 }
191
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 */
222 };
223
224 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
225 {
226 u32 index;
227
228 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
229 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
230 return index + 1;
231
232 return 0;
233 }
234
235 #if defined(CONFIG_APM821XX)
236
237 void get_sys_info(sys_info_t *sysInfo)
238 {
239 unsigned long plld;
240 unsigned long temp;
241 unsigned long mul;
242 unsigned long cpudv;
243 unsigned long plb2dv;
244 unsigned long ddr2dv;
245
246 /* Calculate Forward divisor A and Feeback divisor */
247 mfcpr(CPR0_PLLD, plld);
248
249 temp = CPR0_PLLD_FWDVA(plld);
250 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
251
252 temp = CPR0_PLLD_FDV(plld);
253 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
254
255 /* Calculate OPB clock divisor */
256 mfcpr(CPR0_OPBD, temp);
257 temp = CPR0_OPBD_OPBDV(temp);
258 sysInfo->pllOpbDiv = temp ? temp : 4;
259
260 /* Calculate Peripheral clock divisor */
261 mfcpr(CPR0_PERD, temp);
262 temp = CPR0_PERD_PERDV(temp);
263 sysInfo->pllExtBusDiv = temp ? temp : 4;
264
265 /* Calculate CPU clock divisor */
266 mfcpr(CPR0_CPUD, temp);
267 temp = CPR0_CPUD_CPUDV(temp);
268 cpudv = temp ? temp : 8;
269
270 /* Calculate PLB2 clock divisor */
271 mfcpr(CPR0_PLB2D, temp);
272 temp = CPR0_PLB2D_PLB2DV(temp);
273 plb2dv = temp ? temp : 4;
274
275 /* Calculate DDR2 clock divisor */
276 mfcpr(CPR0_DDR2D, temp);
277 temp = CPR0_DDR2D_DDR2DV(temp);
278 ddr2dv = temp ? temp : 4;
279
280 /* Calculate 'M' based on feedback source */
281 mfcpr(CPR0_PLLC, temp);
282 temp = CPR0_PLLC_SEL(temp);
283 if (temp == 0) {
284 /* PLL internal feedback */
285 mul = sysInfo->pllFbkDiv;
286 } else {
287 /* PLL PerClk feedback */
288 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
289 * plb2dv * 2 * sysInfo->pllOpbDiv *
290 sysInfo->pllExtBusDiv;
291 }
292
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;
304 }
305
306 #else
307 /*
308 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
309 * with latest EAS
310 */
311 void get_sys_info (sys_info_t * sysInfo)
312 {
313 unsigned long strp0;
314 unsigned long strp1;
315 unsigned long temp;
316 unsigned long m;
317 unsigned long plbedv0;
318
319 /* Extract configured divisors */
320 mfsdr(SDR0_SDSTP0, strp0);
321 mfsdr(SDR0_SDSTP1, strp1);
322
323 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
324 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
325
326 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
327 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
328
329 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
330 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
331
332 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
333 sysInfo->pllOpbDiv = temp ? temp : 4;
334
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;
338
339 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
340 plbedv0 = temp ? temp: 8;
341
342 /* Calculate 'M' based on feedback source */
343 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
344 if (temp == 0) {
345 /* PLL internal feedback */
346 m = sysInfo->pllFbkDiv;
347 } else {
348 /* PLL PerClk feedback */
349 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
350 sysInfo->pllExtBusDiv;
351 }
352
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;
361
362 return;
363 }
364 #endif
365
366 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
367 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
368 void get_sys_info (sys_info_t *sysInfo)
369 {
370 unsigned long temp;
371 unsigned long reg;
372 unsigned long lfdiv;
373 unsigned long m;
374 unsigned long prbdv0;
375 /*
376 WARNING: ASSUMES the following:
377 ENG=1
378 PRADV0=1
379 PRBDV0=1
380 */
381
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;
391
392 mfcpr(CPR0_OPBD0, reg);
393 temp = (reg & OPBDDV_MASK) >> 24;
394 sysInfo->pllOpbDiv = temp ? temp : 4;
395
396 mfcpr(CPR0_PERD, reg);
397 temp = (reg & PERDV_MASK) >> 24;
398 sysInfo->pllExtBusDiv = temp ? temp : 8;
399
400 mfcpr(CPR0_PRIMBD0, reg);
401 temp = (reg & PRBDV_MASK) >> 24;
402 prbdv0 = temp ? temp : 8;
403
404 mfcpr(CPR0_SPCID, reg);
405 temp = (reg & SPCID_MASK) >> 24;
406 sysInfo->pllPciDiv = temp ? temp : 4;
407
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;
417 else /* PLLOUTB */
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
419 }
420 else if (temp == 1) /* CPU output */
421 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
422 else /* PerClk */
423 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
424
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;
433
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;
440 else
441 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
442 }
443 else /* Internal clock */
444 sysInfo->freqTmrClk = sysInfo->freqProcessor;
445 }
446
447 /********************************************
448 * get_PCI_freq
449 * return PCI bus freq in Hz
450 *********************************************/
451 ulong get_PCI_freq (void)
452 {
453 sys_info_t sys_info;
454 get_sys_info (&sys_info);
455 return sys_info.freqPCI;
456 }
457
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)
461 {
462 unsigned long strp0;
463 unsigned long temp;
464 unsigned long m;
465
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);
474
475 /* Calculate 'M' based on feedback source */
476 if( strp0 & PLLSYS0_EXTSL_MASK )
477 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
478 else
479 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
480
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;
490 }
491 #else
492
493 #if !defined(CONFIG_XILINX_440)
494 void get_sys_info (sys_info_t * sysInfo)
495 {
496 unsigned long strp0;
497 unsigned long strp1;
498 unsigned long temp;
499 unsigned long temp1;
500 unsigned long lfdiv;
501 unsigned long m;
502 unsigned long prbdv0;
503
504 #if defined(CONFIG_YUCCA)
505 unsigned long sys_freq;
506 unsigned long sys_per=0;
507 unsigned long msr;
508 unsigned long pci_clock_per;
509 unsigned long sdr_ddrpll;
510
511 /*-------------------------------------------------------------------------+
512 | Get the system clock period.
513 +-------------------------------------------------------------------------*/
514 sys_per = determine_sysper();
515
516 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
517
518 /*-------------------------------------------------------------------------+
519 | Calculate the system clock speed from the period.
520 +-------------------------------------------------------------------------*/
521 sys_freq = (ONE_BILLION / sys_per) * 1000;
522 #endif
523
524 /* Extract configured divisors */
525 mfsdr( SDR0_SDSTP0,strp0 );
526 mfsdr( SDR0_SDSTP1,strp1 );
527
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;
539
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;
547 if (!temp)
548 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
549 else
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
551 }
552 else if (temp == 1) /* CPU output */
553 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
554 else /* PerClk */
555 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
556
557 /* Now calculate the individual clocks */
558 #if defined(CONFIG_YUCCA)
559 sysInfo->freqVCOMhz = (m * sys_freq) ;
560 #else
561 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
562 #endif
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;
567
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));
574 #endif
575
576 sysInfo->freqUART = sysInfo->freqPLB;
577 }
578
579 #endif
580 #endif /* CONFIG_XILINX_440 */
581
582 #if defined(CONFIG_YUCCA)
583 unsigned long determine_sysper(void)
584 {
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;
592 int extClkVal;
593
594 /*-------------------------------------------------------------------------+
595 | Read FPGA reg 0 and reg 1 to get FPGA reg information
596 +-------------------------------------------------------------------------*/
597 fpga_clocking_reg = in16(FPGA_REG16);
598
599
600 /* Determine Master Clock Source Selection */
601 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
602
603 switch(master_clock_selection) {
604 case FPGA_REG16_MASTER_CLK_66_66:
605 master_clock_per = PERIOD_66_66MHZ;
606 break;
607 case FPGA_REG16_MASTER_CLK_50:
608 master_clock_per = PERIOD_50_00MHZ;
609 break;
610 case FPGA_REG16_MASTER_CLK_33_33:
611 master_clock_per = PERIOD_33_33MHZ;
612 break;
613 case FPGA_REG16_MASTER_CLK_25:
614 master_clock_per = PERIOD_25_00MHZ;
615 break;
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;
623 } else {
624 /* Unsupported */
625 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
626 hang();
627 }
628 break;
629 default:
630 /* Unsupported */
631 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
632 hang();
633 break;
634 }
635
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;
640 else
641 fb_div_selection = FPGA_FB_DIV_12;
642 } else {
643 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
644 fb_div_selection = FPGA_FB_DIV_10;
645 else
646 fb_div_selection = FPGA_FB_DIV_20;
647 }
648
649 /* Determine VCO divisors values */
650 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
651
652 switch(vco_div_reg_value) {
653 case FPGA_REG16_VCO_DIV_4:
654 vco_div_selection = FPGA_VCO_DIV_4;
655 break;
656 case FPGA_REG16_VCO_DIV_6:
657 vco_div_selection = FPGA_VCO_DIV_6;
658 break;
659 case FPGA_REG16_VCO_DIV_8:
660 vco_div_selection = FPGA_VCO_DIV_8;
661 break;
662 case FPGA_REG16_VCO_DIV_10:
663 default:
664 vco_div_selection = FPGA_VCO_DIV_10;
665 break;
666 }
667
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;
676 }
677 break;
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;
684 }
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;
690 }
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;
698 }
699 break;
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;
706 }
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;
712 }
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;
718 }
719 break;
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;
728 }
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;
734 }
735 if (fb_div_selection == FPGA_FB_DIV_12) {
736 if (vco_div_selection == FPGA_VCO_DIV_8)
737 sys_per = PERIOD_100_00MHZ;
738 }
739 break;
740 default:
741 break;
742 }
743
744 if (sys_per == 0) {
745 /* Other combinations are not supported */
746 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
747 hang();
748 }
749 } else {
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;
754 }
755
756 return(sys_per);
757 }
758
759 /*-------------------------------------------------------------------------+
760 | determine_pci_clock_per.
761 +-------------------------------------------------------------------------*/
762 unsigned long determine_pci_clock_per(void)
763 {
764 unsigned long pci_clock_selection, pci_period;
765
766 /*-------------------------------------------------------------------------+
767 | Read FPGA reg 6 to get PCI 0 FPGA reg information
768 +-------------------------------------------------------------------------*/
769 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
770
771
772 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
773
774 switch (pci_clock_selection) {
775 case FPGA_REG16_PCI0_CLK_133_33:
776 pci_period = PERIOD_133_33MHZ;
777 break;
778 case FPGA_REG16_PCI0_CLK_100:
779 pci_period = PERIOD_100_00MHZ;
780 break;
781 case FPGA_REG16_PCI0_CLK_66_66:
782 pci_period = PERIOD_66_66MHZ;
783 break;
784 default:
785 pci_period = PERIOD_33_33MHZ;;
786 break;
787 }
788
789 return(pci_period);
790 }
791 #endif
792
793 #elif defined(CONFIG_XILINX_405)
794 extern void get_sys_info (sys_info_t * sysInfo);
795 extern ulong get_PCI_freq (void);
796
797 #elif defined(CONFIG_405)
798
799 void get_sys_info (sys_info_t * sysInfo)
800 {
801 sysInfo->freqVCOMhz=3125000;
802 sysInfo->freqProcessor=12*1000*1000;
803 sysInfo->freqPLB=50*1000*1000;
804 sysInfo->freqPCI=66*1000*1000;
805 }
806
807 #elif defined(CONFIG_405EP)
808 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
809 {
810 unsigned long pllmr0;
811 unsigned long pllmr1;
812 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
813 unsigned long m;
814 unsigned long pllmr0_ccdv;
815
816 /*
817 * Read PLL Mode registers
818 */
819 pllmr0 = mfdcr (CPC0_PLLMR0);
820 pllmr1 = mfdcr (CPC0_PLLMR1);
821
822 /*
823 * Determine forward divider A
824 */
825 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
826
827 /*
828 * Determine forward divider B (should be equal to A)
829 */
830 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
831
832 /*
833 * Determine FBK_DIV.
834 */
835 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
836 if (sysInfo->pllFbkDiv == 0)
837 sysInfo->pllFbkDiv = 16;
838
839 /*
840 * Determine PLB_DIV.
841 */
842 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
843
844 /*
845 * Determine PCI_DIV.
846 */
847 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
848
849 /*
850 * Determine EXTBUS_DIV.
851 */
852 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
853
854 /*
855 * Determine OPB_DIV.
856 */
857 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
858
859 /*
860 * Determine the M factor
861 */
862 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
863
864 /*
865 * Determine VCO clock frequency
866 */
867 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
868 (unsigned long long)sysClkPeriodPs;
869
870 /*
871 * Determine CPU clock frequency
872 */
873 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
874 if (pllmr1 & PLLMR1_SSCS_MASK) {
875 /*
876 * This is true if FWDVA == FWDVB:
877 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
878 * / pllmr0_ccdv;
879 */
880 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
881 / sysInfo->pllFwdDiv / pllmr0_ccdv;
882 } else {
883 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
884 }
885
886 /*
887 * Determine PLB clock frequency
888 */
889 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
890
891 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
892
893 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
894
895 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
896 }
897
898
899 /********************************************
900 * get_PCI_freq
901 * return PCI bus freq in Hz
902 *********************************************/
903 ulong get_PCI_freq (void)
904 {
905 ulong val;
906 PPC4xx_SYS_INFO sys_info;
907
908 get_sys_info (&sys_info);
909 val = sys_info.freqPLB / sys_info.pllPciDiv;
910 return val;
911 }
912
913 #elif defined(CONFIG_405EZ)
914 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
915 {
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;
921 unsigned long m;
922 unsigned long plloutb;
923
924 /*
925 * Read PLL Mode registers
926 */
927 mfcpr(CPR0_PLLD, cpr_plld);
928 mfcpr(CPR0_PLLC, cpr_pllc);
929
930 /*
931 * Determine forward divider A
932 */
933 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
934
935 /*
936 * Determine forward divider B
937 */
938 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
939 if (sysInfo->pllFwdDivB == 0)
940 sysInfo->pllFwdDivB = 8;
941
942 /*
943 * Determine FBK_DIV.
944 */
945 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
946 if (sysInfo->pllFbkDiv == 0)
947 sysInfo->pllFbkDiv = 256;
948
949 /*
950 * Read CPR_PRIMAD register
951 */
952 mfcpr(CPR0_PRIMAD, cpr_primad);
953
954 /*
955 * Determine PLB_DIV.
956 */
957 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
958 if (sysInfo->pllPlbDiv == 0)
959 sysInfo->pllPlbDiv = 16;
960
961 /*
962 * Determine EXTBUS_DIV.
963 */
964 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
965 if (sysInfo->pllExtBusDiv == 0)
966 sysInfo->pllExtBusDiv = 16;
967
968 /*
969 * Determine OPB_DIV.
970 */
971 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
972 if (sysInfo->pllOpbDiv == 0)
973 sysInfo->pllOpbDiv = 16;
974
975 /*
976 * Determine the M factor
977 */
978 if (cpr_pllc & PLLC_SRC_MASK)
979 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
980 else
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
982
983 /*
984 * Determine VCO clock frequency
985 */
986 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
987 (unsigned long long)sysClkPeriodPs;
988
989 /*
990 * Determine CPU clock frequency
991 */
992 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
993 if (primad_cpudv == 0)
994 primad_cpudv = 16;
995
996 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
997 sysInfo->pllFwdDiv / primad_cpudv;
998
999 /*
1000 * Determine PLB clock frequency
1001 */
1002 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1003 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1004
1005 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1006 sysInfo->pllOpbDiv;
1007
1008 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1009 sysInfo->pllExtBusDiv;
1010
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;
1015 }
1016
1017 #elif defined(CONFIG_405EX)
1018
1019 /*
1020 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1021 * We need the specs!!!!
1022 */
1023 static unsigned char get_fbdv(unsigned char index)
1024 {
1025 unsigned char ret = 0;
1026 /* This is table should be 256 bytes.
1027 * Only take first 52 values.
1028 */
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,
1043
1044 };
1045
1046 if ((index & 0x7f) == 0)
1047 return 1;
1048 while (ret < sizeof (fbdv_tb)) {
1049 if (fbdv_tb[ret] == index)
1050 break;
1051 ret++;
1052 }
1053 ret++;
1054
1055 return ret;
1056 }
1057
1058 #define PLL_FBK_PLL_LOCAL 0
1059 #define PLL_FBK_CPU 1
1060 #define PLL_FBK_PERCLK 5
1061
1062 void get_sys_info (sys_info_t * sysInfo)
1063 {
1064 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1065 unsigned long m = 1;
1066 unsigned int tmp;
1067 unsigned char fwdva[16] = {
1068 1, 2, 14, 9, 4, 11, 16, 13,
1069 12, 5, 6, 15, 10, 7, 8, 3,
1070 };
1071 unsigned char sel, cpudv0, plb2xDiv;
1072
1073 mfcpr(CPR0_PLLD, tmp);
1074
1075 /*
1076 * Determine forward divider A
1077 */
1078 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1079
1080 /*
1081 * Determine FBK_DIV.
1082 */
1083 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1084
1085 /*
1086 * Determine PLBDV0
1087 */
1088 sysInfo->pllPlbDiv = 2;
1089
1090 /*
1091 * Determine PERDV0
1092 */
1093 mfcpr(CPR0_PERD, tmp);
1094 tmp = (tmp >> 24) & 0x03;
1095 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1096
1097 /*
1098 * Determine OPBDV0
1099 */
1100 mfcpr(CPR0_OPBD0, tmp);
1101 tmp = (tmp >> 24) & 0x03;
1102 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1103
1104 /* Determine PLB2XDV0 */
1105 mfcpr(CPR0_PLBD, tmp);
1106 tmp = (tmp >> 16) & 0x07;
1107 plb2xDiv = (tmp == 0) ? 8 : tmp;
1108
1109 /* Determine CPUDV0 */
1110 mfcpr(CPR0_CPUD, tmp);
1111 tmp = (tmp >> 24) & 0x07;
1112 cpudv0 = (tmp == 0) ? 8 : tmp;
1113
1114 /* Determine SEL(5:7) in CPR0_PLLC */
1115 mfcpr(CPR0_PLLC, tmp);
1116 sel = (tmp >> 24) & 0x07;
1117
1118 /*
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
1123 *
1124 */
1125 switch (sel) {
1126 case PLL_FBK_CPU:
1127 m = sysInfo->pllFwdDiv * cpudv0;
1128 break;
1129 case PLL_FBK_PERCLK:
1130 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1131 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1132 break;
1133 case PLL_FBK_PLL_LOCAL:
1134 break;
1135 default:
1136 printf("%s unknown m\n", __FUNCTION__);
1137 return;
1138
1139 }
1140 m *= sysInfo->pllFbkDiv;
1141
1142 /*
1143 * Determine VCO clock frequency
1144 */
1145 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1146 (unsigned long long)sysClkPeriodPs;
1147
1148 /*
1149 * Determine CPU clock frequency
1150 */
1151 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1152
1153 /*
1154 * Determine PLB clock frequency, ddr1x should be the same
1155 */
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;
1161 }
1162
1163 #endif
1164
1165 int get_clocks (void)
1166 {
1167 sys_info_t sys_info;
1168
1169 get_sys_info (&sys_info);
1170 gd->cpu_clk = sys_info.freqProcessor;
1171 gd->bus_clk = sys_info.freqPLB;
1172
1173 return (0);
1174 }
1175
1176
1177 /********************************************
1178 * get_bus_freq
1179 * return PLB bus freq in Hz
1180 *********************************************/
1181 ulong get_bus_freq (ulong dummy)
1182 {
1183 ulong val;
1184
1185 #if defined(CONFIG_405GP) || \
1186 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1187 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1188 defined(CONFIG_440)
1189 sys_info_t sys_info;
1190
1191 get_sys_info (&sys_info);
1192 val = sys_info.freqPLB;
1193 #else
1194 # error get_bus_freq() not implemented
1195 #endif
1196
1197 return val;
1198 }
1199
1200 ulong get_OPB_freq (void)
1201 {
1202 PPC4xx_SYS_INFO sys_info;
1203
1204 get_sys_info (&sys_info);
1205
1206 return sys_info.freqOPB;
1207 }