]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/powerpc/cpu/ppc4xx/speed.c
ppc4xx: Remove support for PPC405CR CPUs
[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 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
23
24 #if defined(CONFIG_405GP)
25
26 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
27 {
28 unsigned long pllmr;
29 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
30 uint pvr = get_pvr();
31 unsigned long psr;
32 unsigned long m;
33
34 /*
35 * Read PLL Mode register
36 */
37 pllmr = mfdcr (CPC0_PLLMR);
38
39 /*
40 * Read Pin Strapping register
41 */
42 psr = mfdcr (CPC0_PSR);
43
44 /*
45 * Determine FWD_DIV.
46 */
47 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
48
49 /*
50 * Determine FBK_DIV.
51 */
52 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
53 if (sysInfo->pllFbkDiv == 0) {
54 sysInfo->pllFbkDiv = 16;
55 }
56
57 /*
58 * Determine PLB_DIV.
59 */
60 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
61
62 /*
63 * Determine PCI_DIV.
64 */
65 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
66
67 /*
68 * Determine EXTBUS_DIV.
69 */
70 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
71
72 /*
73 * Determine OPB_DIV.
74 */
75 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
76
77 /*
78 * Check if PPC405GPr used (mask minor revision field)
79 */
80 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
81 /*
82 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
83 */
84 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
85
86 /*
87 * Determine factor m depending on PLL feedback clock source
88 */
89 if (!(psr & PSR_PCI_ASYNC_EN)) {
90 if (psr & PSR_NEW_MODE_EN) {
91 /*
92 * sync pci clock used as feedback (new mode)
93 */
94 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
95 } else {
96 /*
97 * sync pci clock used as feedback (legacy mode)
98 */
99 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
100 }
101 } else if (psr & PSR_NEW_MODE_EN) {
102 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
103 /*
104 * PerClk used as feedback (new mode)
105 */
106 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
107 } else {
108 /*
109 * CPU clock used as feedback (new mode)
110 */
111 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
112 }
113 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
114 /*
115 * PerClk used as feedback (legacy mode)
116 */
117 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
118 } else {
119 /*
120 * PLB clock used as feedback (legacy mode)
121 */
122 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
123 }
124
125 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
126 (unsigned long long)sysClkPeriodPs;
127 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
128 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
129 } else {
130 /*
131 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
132 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
133 * to make sure it is within the proper range.
134 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
135 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
136 */
137 if (sysInfo->pllFwdDiv == 1) {
138 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
139 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
140 } else {
141 sysInfo->freqVCOHz = ( 1000000000000LL *
142 (unsigned long long)sysInfo->pllFwdDiv *
143 (unsigned long long)sysInfo->pllFbkDiv *
144 (unsigned long long)sysInfo->pllPlbDiv
145 ) / (unsigned long long)sysClkPeriodPs;
146 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
147 sysInfo->pllFbkDiv)) * 10000;
148 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
149 }
150 }
151
152 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
153 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
154 sysInfo->freqUART = sysInfo->freqProcessor;
155 }
156
157
158 /********************************************
159 * get_PCI_freq
160 * return PCI bus freq in Hz
161 *********************************************/
162 ulong get_PCI_freq (void)
163 {
164 ulong val;
165 PPC4xx_SYS_INFO sys_info;
166
167 get_sys_info (&sys_info);
168 val = sys_info.freqPLB / sys_info.pllPciDiv;
169 return val;
170 }
171
172
173 #elif defined(CONFIG_440)
174
175 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
176 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
177 static u8 pll_fwdv_multi_bits[] = {
178 /* values for: 1 - 16 */
179 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
180 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
181 };
182
183 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
184 {
185 u32 index;
186
187 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
188 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
189 return index + 1;
190
191 return 0;
192 }
193
194 static u8 pll_fbdv_multi_bits[] = {
195 /* values for: 1 - 100 */
196 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
197 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
198 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
199 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
200 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
201 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
202 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
203 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
204 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
205 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
206 /* values for: 101 - 200 */
207 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
208 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
209 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
210 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
211 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
212 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
213 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
214 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
215 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
216 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
217 /* values for: 201 - 255 */
218 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
219 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
220 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
221 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
222 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
223 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
224 };
225
226 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
227 {
228 u32 index;
229
230 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
231 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
232 return index + 1;
233
234 return 0;
235 }
236
237 #if defined(CONFIG_APM821XX)
238
239 void get_sys_info(sys_info_t *sysInfo)
240 {
241 unsigned long plld;
242 unsigned long temp;
243 unsigned long mul;
244 unsigned long cpudv;
245 unsigned long plb2dv;
246 unsigned long ddr2dv;
247
248 /* Calculate Forward divisor A and Feeback divisor */
249 mfcpr(CPR0_PLLD, plld);
250
251 temp = CPR0_PLLD_FWDVA(plld);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
253
254 temp = CPR0_PLLD_FDV(plld);
255 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
256
257 /* Calculate OPB clock divisor */
258 mfcpr(CPR0_OPBD, temp);
259 temp = CPR0_OPBD_OPBDV(temp);
260 sysInfo->pllOpbDiv = temp ? temp : 4;
261
262 /* Calculate Peripheral clock divisor */
263 mfcpr(CPR0_PERD, temp);
264 temp = CPR0_PERD_PERDV(temp);
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
266
267 /* Calculate CPU clock divisor */
268 mfcpr(CPR0_CPUD, temp);
269 temp = CPR0_CPUD_CPUDV(temp);
270 cpudv = temp ? temp : 8;
271
272 /* Calculate PLB2 clock divisor */
273 mfcpr(CPR0_PLB2D, temp);
274 temp = CPR0_PLB2D_PLB2DV(temp);
275 plb2dv = temp ? temp : 4;
276
277 /* Calculate DDR2 clock divisor */
278 mfcpr(CPR0_DDR2D, temp);
279 temp = CPR0_DDR2D_DDR2DV(temp);
280 ddr2dv = temp ? temp : 4;
281
282 /* Calculate 'M' based on feedback source */
283 mfcpr(CPR0_PLLC, temp);
284 temp = CPR0_PLLC_SEL(temp);
285 if (temp == 0) {
286 /* PLL internal feedback */
287 mul = sysInfo->pllFbkDiv;
288 } else {
289 /* PLL PerClk feedback */
290 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
291 * plb2dv * 2 * sysInfo->pllOpbDiv *
292 sysInfo->pllExtBusDiv;
293 }
294
295 /* Now calculate the individual clocks */
296 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
297 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
298 sysInfo->pllFwdDivA / cpudv;
299 sysInfo->freqPLB = sysInfo->freqVCOMhz /
300 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
301 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
302 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
303 sysInfo->freqDDR = sysInfo->freqVCOMhz /
304 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
305 sysInfo->freqUART = sysInfo->freqPLB;
306 }
307
308 #else
309 /*
310 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
311 * with latest EAS
312 */
313 void get_sys_info (sys_info_t * sysInfo)
314 {
315 unsigned long strp0;
316 unsigned long strp1;
317 unsigned long temp;
318 unsigned long m;
319 unsigned long plbedv0;
320
321 /* Extract configured divisors */
322 mfsdr(SDR0_SDSTP0, strp0);
323 mfsdr(SDR0_SDSTP1, strp1);
324
325 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
326 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
327
328 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
329 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
330
331 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
332 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
333
334 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
335 sysInfo->pllOpbDiv = temp ? temp : 4;
336
337 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
338 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
339 sysInfo->pllExtBusDiv = temp ? temp : 4;
340
341 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
342 plbedv0 = temp ? temp: 8;
343
344 /* Calculate 'M' based on feedback source */
345 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
346 if (temp == 0) {
347 /* PLL internal feedback */
348 m = sysInfo->pllFbkDiv;
349 } else {
350 /* PLL PerClk feedback */
351 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
352 sysInfo->pllExtBusDiv;
353 }
354
355 /* Now calculate the individual clocks */
356 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
357 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
358 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
359 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
360 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
361 sysInfo->freqDDR = sysInfo->freqPLB;
362 sysInfo->freqUART = sysInfo->freqPLB;
363
364 return;
365 }
366 #endif
367
368 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
369 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
370 void get_sys_info (sys_info_t *sysInfo)
371 {
372 unsigned long temp;
373 unsigned long reg;
374 unsigned long lfdiv;
375 unsigned long m;
376 unsigned long prbdv0;
377 /*
378 WARNING: ASSUMES the following:
379 ENG=1
380 PRADV0=1
381 PRBDV0=1
382 */
383
384 /* Decode CPR0_PLLD0 for divisors */
385 mfcpr(CPR0_PLLD, reg);
386 temp = (reg & PLLD_FWDVA_MASK) >> 16;
387 sysInfo->pllFwdDivA = temp ? temp : 16;
388 temp = (reg & PLLD_FWDVB_MASK) >> 8;
389 sysInfo->pllFwdDivB = temp ? temp: 8 ;
390 temp = (reg & PLLD_FBDV_MASK) >> 24;
391 sysInfo->pllFbkDiv = temp ? temp : 32;
392 lfdiv = reg & PLLD_LFBDV_MASK;
393
394 mfcpr(CPR0_OPBD0, reg);
395 temp = (reg & OPBDDV_MASK) >> 24;
396 sysInfo->pllOpbDiv = temp ? temp : 4;
397
398 mfcpr(CPR0_PERD, reg);
399 temp = (reg & PERDV_MASK) >> 24;
400 sysInfo->pllExtBusDiv = temp ? temp : 8;
401
402 mfcpr(CPR0_PRIMBD0, reg);
403 temp = (reg & PRBDV_MASK) >> 24;
404 prbdv0 = temp ? temp : 8;
405
406 mfcpr(CPR0_SPCID, reg);
407 temp = (reg & SPCID_MASK) >> 24;
408 sysInfo->pllPciDiv = temp ? temp : 4;
409
410 /* Calculate 'M' based on feedback source */
411 mfsdr(SDR0_SDSTP0, reg);
412 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
413 if (temp == 0) { /* PLL output */
414 /* Figure which pll to use */
415 mfcpr(CPR0_PLLC, reg);
416 temp = (reg & PLLC_SRC_MASK) >> 29;
417 if (!temp) /* PLLOUTA */
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
419 else /* PLLOUTB */
420 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
421 }
422 else if (temp == 1) /* CPU output */
423 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
424 else /* PerClk */
425 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
426
427 /* Now calculate the individual clocks */
428 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
429 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
430 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
431 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
432 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
433 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
434 sysInfo->freqUART = sysInfo->freqPLB;
435
436 /* Figure which timer source to use */
437 if (mfspr(SPRN_CCR1) & 0x0080) {
438 /* External Clock, assume same as SYS_CLK */
439 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
440 if (CONFIG_SYS_CLK_FREQ > temp)
441 sysInfo->freqTmrClk = temp;
442 else
443 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
444 }
445 else /* Internal clock */
446 sysInfo->freqTmrClk = sysInfo->freqProcessor;
447 }
448
449 /********************************************
450 * get_PCI_freq
451 * return PCI bus freq in Hz
452 *********************************************/
453 ulong get_PCI_freq (void)
454 {
455 sys_info_t sys_info;
456 get_sys_info (&sys_info);
457 return sys_info.freqPCI;
458 }
459
460 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
461 && !defined(CONFIG_XILINX_440)
462 void get_sys_info (sys_info_t * sysInfo)
463 {
464 unsigned long strp0;
465 unsigned long temp;
466 unsigned long m;
467
468 /* Extract configured divisors */
469 strp0 = mfdcr( CPC0_STRP0 );
470 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
471 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
472 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
473 sysInfo->pllFbkDiv = temp ? temp : 16;
474 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
475 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
476
477 /* Calculate 'M' based on feedback source */
478 if( strp0 & PLLSYS0_EXTSL_MASK )
479 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
480 else
481 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
482
483 /* Now calculate the individual clocks */
484 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
485 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
486 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
487 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
488 sysInfo->freqPLB >>= 1;
489 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
490 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
491 sysInfo->freqUART = sysInfo->freqPLB;
492 }
493 #else
494
495 #if !defined(CONFIG_XILINX_440)
496 void get_sys_info (sys_info_t * sysInfo)
497 {
498 unsigned long strp0;
499 unsigned long strp1;
500 unsigned long temp;
501 unsigned long temp1;
502 unsigned long lfdiv;
503 unsigned long m;
504 unsigned long prbdv0;
505
506 #if defined(CONFIG_YUCCA)
507 unsigned long sys_freq;
508 unsigned long sys_per=0;
509 unsigned long msr;
510 unsigned long pci_clock_per;
511 unsigned long sdr_ddrpll;
512
513 /*-------------------------------------------------------------------------+
514 | Get the system clock period.
515 +-------------------------------------------------------------------------*/
516 sys_per = determine_sysper();
517
518 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
519
520 /*-------------------------------------------------------------------------+
521 | Calculate the system clock speed from the period.
522 +-------------------------------------------------------------------------*/
523 sys_freq = (ONE_BILLION / sys_per) * 1000;
524 #endif
525
526 /* Extract configured divisors */
527 mfsdr( SDR0_SDSTP0,strp0 );
528 mfsdr( SDR0_SDSTP1,strp1 );
529
530 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
531 sysInfo->pllFwdDivA = temp ? temp : 16 ;
532 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
533 sysInfo->pllFwdDivB = temp ? temp: 8 ;
534 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
535 sysInfo->pllFbkDiv = temp ? temp : 32;
536 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
537 sysInfo->pllOpbDiv = temp ? temp : 4;
538 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
539 sysInfo->pllExtBusDiv = temp ? temp : 4;
540 prbdv0 = (strp0 >> 2) & 0x7;
541
542 /* Calculate 'M' based on feedback source */
543 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
544 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
545 lfdiv = temp1 ? temp1 : 64;
546 if (temp == 0) { /* PLL output */
547 /* Figure which pll to use */
548 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
549 if (!temp)
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
551 else
552 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
553 }
554 else if (temp == 1) /* CPU output */
555 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
556 else /* PerClk */
557 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
558
559 /* Now calculate the individual clocks */
560 #if defined(CONFIG_YUCCA)
561 sysInfo->freqVCOMhz = (m * sys_freq) ;
562 #else
563 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
564 #endif
565 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
566 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
567 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
568 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
569
570 #if defined(CONFIG_YUCCA)
571 /* Determine PCI Clock Period */
572 pci_clock_per = determine_pci_clock_per();
573 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
574 mfsdr(SDR0_DDR0, sdr_ddrpll);
575 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
576 #endif
577
578 sysInfo->freqUART = sysInfo->freqPLB;
579 }
580
581 #endif
582 #endif /* CONFIG_XILINX_440 */
583
584 #if defined(CONFIG_YUCCA)
585 unsigned long determine_sysper(void)
586 {
587 unsigned int fpga_clocking_reg;
588 unsigned int master_clock_selection;
589 unsigned long master_clock_per = 0;
590 unsigned long fb_div_selection;
591 unsigned int vco_div_reg_value;
592 unsigned long vco_div_selection;
593 unsigned long sys_per = 0;
594 int extClkVal;
595
596 /*-------------------------------------------------------------------------+
597 | Read FPGA reg 0 and reg 1 to get FPGA reg information
598 +-------------------------------------------------------------------------*/
599 fpga_clocking_reg = in16(FPGA_REG16);
600
601
602 /* Determine Master Clock Source Selection */
603 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
604
605 switch(master_clock_selection) {
606 case FPGA_REG16_MASTER_CLK_66_66:
607 master_clock_per = PERIOD_66_66MHZ;
608 break;
609 case FPGA_REG16_MASTER_CLK_50:
610 master_clock_per = PERIOD_50_00MHZ;
611 break;
612 case FPGA_REG16_MASTER_CLK_33_33:
613 master_clock_per = PERIOD_33_33MHZ;
614 break;
615 case FPGA_REG16_MASTER_CLK_25:
616 master_clock_per = PERIOD_25_00MHZ;
617 break;
618 case FPGA_REG16_MASTER_CLK_EXT:
619 if ((extClkVal==EXTCLK_33_33)
620 && (extClkVal==EXTCLK_50)
621 && (extClkVal==EXTCLK_66_66)
622 && (extClkVal==EXTCLK_83)) {
623 /* calculate master clock period from external clock value */
624 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
625 } else {
626 /* Unsupported */
627 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
628 hang();
629 }
630 break;
631 default:
632 /* Unsupported */
633 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
634 hang();
635 break;
636 }
637
638 /* Determine FB divisors values */
639 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
640 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
641 fb_div_selection = FPGA_FB_DIV_6;
642 else
643 fb_div_selection = FPGA_FB_DIV_12;
644 } else {
645 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
646 fb_div_selection = FPGA_FB_DIV_10;
647 else
648 fb_div_selection = FPGA_FB_DIV_20;
649 }
650
651 /* Determine VCO divisors values */
652 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
653
654 switch(vco_div_reg_value) {
655 case FPGA_REG16_VCO_DIV_4:
656 vco_div_selection = FPGA_VCO_DIV_4;
657 break;
658 case FPGA_REG16_VCO_DIV_6:
659 vco_div_selection = FPGA_VCO_DIV_6;
660 break;
661 case FPGA_REG16_VCO_DIV_8:
662 vco_div_selection = FPGA_VCO_DIV_8;
663 break;
664 case FPGA_REG16_VCO_DIV_10:
665 default:
666 vco_div_selection = FPGA_VCO_DIV_10;
667 break;
668 }
669
670 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
671 switch(master_clock_per) {
672 case PERIOD_25_00MHZ:
673 if (fb_div_selection == FPGA_FB_DIV_12) {
674 if (vco_div_selection == FPGA_VCO_DIV_4)
675 sys_per = PERIOD_75_00MHZ;
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_50_00MHZ;
678 }
679 break;
680 case PERIOD_33_33MHZ:
681 if (fb_div_selection == FPGA_FB_DIV_6) {
682 if (vco_div_selection == FPGA_VCO_DIV_4)
683 sys_per = PERIOD_50_00MHZ;
684 if (vco_div_selection == FPGA_VCO_DIV_6)
685 sys_per = PERIOD_33_33MHZ;
686 }
687 if (fb_div_selection == FPGA_FB_DIV_10) {
688 if (vco_div_selection == FPGA_VCO_DIV_4)
689 sys_per = PERIOD_83_33MHZ;
690 if (vco_div_selection == FPGA_VCO_DIV_10)
691 sys_per = PERIOD_33_33MHZ;
692 }
693 if (fb_div_selection == FPGA_FB_DIV_12) {
694 if (vco_div_selection == FPGA_VCO_DIV_4)
695 sys_per = PERIOD_100_00MHZ;
696 if (vco_div_selection == FPGA_VCO_DIV_6)
697 sys_per = PERIOD_66_66MHZ;
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_50_00MHZ;
700 }
701 break;
702 case PERIOD_50_00MHZ:
703 if (fb_div_selection == FPGA_FB_DIV_6) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_75_00MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_6)
707 sys_per = PERIOD_50_00MHZ;
708 }
709 if (fb_div_selection == FPGA_FB_DIV_10) {
710 if (vco_div_selection == FPGA_VCO_DIV_6)
711 sys_per = PERIOD_83_33MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_10)
713 sys_per = PERIOD_50_00MHZ;
714 }
715 if (fb_div_selection == FPGA_FB_DIV_12) {
716 if (vco_div_selection == FPGA_VCO_DIV_6)
717 sys_per = PERIOD_100_00MHZ;
718 if (vco_div_selection == FPGA_VCO_DIV_8)
719 sys_per = PERIOD_75_00MHZ;
720 }
721 break;
722 case PERIOD_66_66MHZ:
723 if (fb_div_selection == FPGA_FB_DIV_6) {
724 if (vco_div_selection == FPGA_VCO_DIV_4)
725 sys_per = PERIOD_100_00MHZ;
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_66_66MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_8)
729 sys_per = PERIOD_50_00MHZ;
730 }
731 if (fb_div_selection == FPGA_FB_DIV_10) {
732 if (vco_div_selection == FPGA_VCO_DIV_8)
733 sys_per = PERIOD_83_33MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_10)
735 sys_per = PERIOD_66_66MHZ;
736 }
737 if (fb_div_selection == FPGA_FB_DIV_12) {
738 if (vco_div_selection == FPGA_VCO_DIV_8)
739 sys_per = PERIOD_100_00MHZ;
740 }
741 break;
742 default:
743 break;
744 }
745
746 if (sys_per == 0) {
747 /* Other combinations are not supported */
748 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
749 hang();
750 }
751 } else {
752 /* calcul system clock without cheking */
753 /* if engineering option clock no check is selected */
754 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
755 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
756 }
757
758 return(sys_per);
759 }
760
761 /*-------------------------------------------------------------------------+
762 | determine_pci_clock_per.
763 +-------------------------------------------------------------------------*/
764 unsigned long determine_pci_clock_per(void)
765 {
766 unsigned long pci_clock_selection, pci_period;
767
768 /*-------------------------------------------------------------------------+
769 | Read FPGA reg 6 to get PCI 0 FPGA reg information
770 +-------------------------------------------------------------------------*/
771 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
772
773
774 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
775
776 switch (pci_clock_selection) {
777 case FPGA_REG16_PCI0_CLK_133_33:
778 pci_period = PERIOD_133_33MHZ;
779 break;
780 case FPGA_REG16_PCI0_CLK_100:
781 pci_period = PERIOD_100_00MHZ;
782 break;
783 case FPGA_REG16_PCI0_CLK_66_66:
784 pci_period = PERIOD_66_66MHZ;
785 break;
786 default:
787 pci_period = PERIOD_33_33MHZ;;
788 break;
789 }
790
791 return(pci_period);
792 }
793 #endif
794
795 #elif defined(CONFIG_XILINX_405)
796 extern void get_sys_info (sys_info_t * sysInfo);
797 extern ulong get_PCI_freq (void);
798
799 #elif defined(CONFIG_405)
800
801 void get_sys_info (sys_info_t * sysInfo)
802 {
803 sysInfo->freqVCOMhz=3125000;
804 sysInfo->freqProcessor=12*1000*1000;
805 sysInfo->freqPLB=50*1000*1000;
806 sysInfo->freqPCI=66*1000*1000;
807 }
808
809 #elif defined(CONFIG_405EP)
810 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
811 {
812 unsigned long pllmr0;
813 unsigned long pllmr1;
814 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
815 unsigned long m;
816 unsigned long pllmr0_ccdv;
817
818 /*
819 * Read PLL Mode registers
820 */
821 pllmr0 = mfdcr (CPC0_PLLMR0);
822 pllmr1 = mfdcr (CPC0_PLLMR1);
823
824 /*
825 * Determine forward divider A
826 */
827 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
828
829 /*
830 * Determine forward divider B (should be equal to A)
831 */
832 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
833
834 /*
835 * Determine FBK_DIV.
836 */
837 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
838 if (sysInfo->pllFbkDiv == 0)
839 sysInfo->pllFbkDiv = 16;
840
841 /*
842 * Determine PLB_DIV.
843 */
844 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
845
846 /*
847 * Determine PCI_DIV.
848 */
849 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
850
851 /*
852 * Determine EXTBUS_DIV.
853 */
854 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
855
856 /*
857 * Determine OPB_DIV.
858 */
859 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
860
861 /*
862 * Determine the M factor
863 */
864 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
865
866 /*
867 * Determine VCO clock frequency
868 */
869 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
870 (unsigned long long)sysClkPeriodPs;
871
872 /*
873 * Determine CPU clock frequency
874 */
875 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
876 if (pllmr1 & PLLMR1_SSCS_MASK) {
877 /*
878 * This is true if FWDVA == FWDVB:
879 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
880 * / pllmr0_ccdv;
881 */
882 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
883 / sysInfo->pllFwdDiv / pllmr0_ccdv;
884 } else {
885 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
886 }
887
888 /*
889 * Determine PLB clock frequency
890 */
891 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
892
893 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
894
895 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
896
897 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
898 }
899
900
901 /********************************************
902 * get_PCI_freq
903 * return PCI bus freq in Hz
904 *********************************************/
905 ulong get_PCI_freq (void)
906 {
907 ulong val;
908 PPC4xx_SYS_INFO sys_info;
909
910 get_sys_info (&sys_info);
911 val = sys_info.freqPLB / sys_info.pllPciDiv;
912 return val;
913 }
914
915 #elif defined(CONFIG_405EZ)
916 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
917 {
918 unsigned long cpr_plld;
919 unsigned long cpr_pllc;
920 unsigned long cpr_primad;
921 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
922 unsigned long primad_cpudv;
923 unsigned long m;
924 unsigned long plloutb;
925
926 /*
927 * Read PLL Mode registers
928 */
929 mfcpr(CPR0_PLLD, cpr_plld);
930 mfcpr(CPR0_PLLC, cpr_pllc);
931
932 /*
933 * Determine forward divider A
934 */
935 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
936
937 /*
938 * Determine forward divider B
939 */
940 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
941 if (sysInfo->pllFwdDivB == 0)
942 sysInfo->pllFwdDivB = 8;
943
944 /*
945 * Determine FBK_DIV.
946 */
947 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
948 if (sysInfo->pllFbkDiv == 0)
949 sysInfo->pllFbkDiv = 256;
950
951 /*
952 * Read CPR_PRIMAD register
953 */
954 mfcpr(CPR0_PRIMAD, cpr_primad);
955
956 /*
957 * Determine PLB_DIV.
958 */
959 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
960 if (sysInfo->pllPlbDiv == 0)
961 sysInfo->pllPlbDiv = 16;
962
963 /*
964 * Determine EXTBUS_DIV.
965 */
966 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
967 if (sysInfo->pllExtBusDiv == 0)
968 sysInfo->pllExtBusDiv = 16;
969
970 /*
971 * Determine OPB_DIV.
972 */
973 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
974 if (sysInfo->pllOpbDiv == 0)
975 sysInfo->pllOpbDiv = 16;
976
977 /*
978 * Determine the M factor
979 */
980 if (cpr_pllc & PLLC_SRC_MASK)
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
982 else
983 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
984
985 /*
986 * Determine VCO clock frequency
987 */
988 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
989 (unsigned long long)sysClkPeriodPs;
990
991 /*
992 * Determine CPU clock frequency
993 */
994 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
995 if (primad_cpudv == 0)
996 primad_cpudv = 16;
997
998 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
999 sysInfo->pllFwdDiv / primad_cpudv;
1000
1001 /*
1002 * Determine PLB clock frequency
1003 */
1004 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1005 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1006
1007 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1008 sysInfo->pllOpbDiv;
1009
1010 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1011 sysInfo->pllExtBusDiv;
1012
1013 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1014 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1015 sysInfo->pllFwdDivB);
1016 sysInfo->freqUART = plloutb;
1017 }
1018
1019 #elif defined(CONFIG_405EX)
1020
1021 /*
1022 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1023 * We need the specs!!!!
1024 */
1025 static unsigned char get_fbdv(unsigned char index)
1026 {
1027 unsigned char ret = 0;
1028 /* This is table should be 256 bytes.
1029 * Only take first 52 values.
1030 */
1031 unsigned char fbdv_tb[] = {
1032 0x00, 0xff, 0x7f, 0xfd,
1033 0x7a, 0xf5, 0x6a, 0xd5,
1034 0x2a, 0xd4, 0x29, 0xd3,
1035 0x26, 0xcc, 0x19, 0xb3,
1036 0x67, 0xce, 0x1d, 0xbb,
1037 0x77, 0xee, 0x5d, 0xba,
1038 0x74, 0xe9, 0x52, 0xa5,
1039 0x4b, 0x96, 0x2c, 0xd8,
1040 0x31, 0xe3, 0x46, 0x8d,
1041 0x1b, 0xb7, 0x6f, 0xde,
1042 0x3d, 0xfb, 0x76, 0xed,
1043 0x5a, 0xb5, 0x6b, 0xd6,
1044 0x2d, 0xdb, 0x36, 0xec,
1045
1046 };
1047
1048 if ((index & 0x7f) == 0)
1049 return 1;
1050 while (ret < sizeof (fbdv_tb)) {
1051 if (fbdv_tb[ret] == index)
1052 break;
1053 ret++;
1054 }
1055 ret++;
1056
1057 return ret;
1058 }
1059
1060 #define PLL_FBK_PLL_LOCAL 0
1061 #define PLL_FBK_CPU 1
1062 #define PLL_FBK_PERCLK 5
1063
1064 void get_sys_info (sys_info_t * sysInfo)
1065 {
1066 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1067 unsigned long m = 1;
1068 unsigned int tmp;
1069 unsigned char fwdva[16] = {
1070 1, 2, 14, 9, 4, 11, 16, 13,
1071 12, 5, 6, 15, 10, 7, 8, 3,
1072 };
1073 unsigned char sel, cpudv0, plb2xDiv;
1074
1075 mfcpr(CPR0_PLLD, tmp);
1076
1077 /*
1078 * Determine forward divider A
1079 */
1080 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1081
1082 /*
1083 * Determine FBK_DIV.
1084 */
1085 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1086
1087 /*
1088 * Determine PLBDV0
1089 */
1090 sysInfo->pllPlbDiv = 2;
1091
1092 /*
1093 * Determine PERDV0
1094 */
1095 mfcpr(CPR0_PERD, tmp);
1096 tmp = (tmp >> 24) & 0x03;
1097 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1098
1099 /*
1100 * Determine OPBDV0
1101 */
1102 mfcpr(CPR0_OPBD0, tmp);
1103 tmp = (tmp >> 24) & 0x03;
1104 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1105
1106 /* Determine PLB2XDV0 */
1107 mfcpr(CPR0_PLBD, tmp);
1108 tmp = (tmp >> 16) & 0x07;
1109 plb2xDiv = (tmp == 0) ? 8 : tmp;
1110
1111 /* Determine CPUDV0 */
1112 mfcpr(CPR0_CPUD, tmp);
1113 tmp = (tmp >> 24) & 0x07;
1114 cpudv0 = (tmp == 0) ? 8 : tmp;
1115
1116 /* Determine SEL(5:7) in CPR0_PLLC */
1117 mfcpr(CPR0_PLLC, tmp);
1118 sel = (tmp >> 24) & 0x07;
1119
1120 /*
1121 * Determine the M factor
1122 * PLL local: M = FBDV
1123 * CPU clock: M = FBDV * FWDVA * CPUDV0
1124 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1125 *
1126 */
1127 switch (sel) {
1128 case PLL_FBK_CPU:
1129 m = sysInfo->pllFwdDiv * cpudv0;
1130 break;
1131 case PLL_FBK_PERCLK:
1132 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1133 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1134 break;
1135 case PLL_FBK_PLL_LOCAL:
1136 break;
1137 default:
1138 printf("%s unknown m\n", __FUNCTION__);
1139 return;
1140
1141 }
1142 m *= sysInfo->pllFbkDiv;
1143
1144 /*
1145 * Determine VCO clock frequency
1146 */
1147 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1148 (unsigned long long)sysClkPeriodPs;
1149
1150 /*
1151 * Determine CPU clock frequency
1152 */
1153 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1154
1155 /*
1156 * Determine PLB clock frequency, ddr1x should be the same
1157 */
1158 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1159 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1160 sysInfo->freqDDR = sysInfo->freqPLB;
1161 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1162 sysInfo->freqUART = sysInfo->freqPLB;
1163 }
1164
1165 #endif
1166
1167 int get_clocks (void)
1168 {
1169 sys_info_t sys_info;
1170
1171 get_sys_info (&sys_info);
1172 gd->cpu_clk = sys_info.freqProcessor;
1173 gd->bus_clk = sys_info.freqPLB;
1174
1175 return (0);
1176 }
1177
1178
1179 /********************************************
1180 * get_bus_freq
1181 * return PLB bus freq in Hz
1182 *********************************************/
1183 ulong get_bus_freq (ulong dummy)
1184 {
1185 ulong val;
1186
1187 #if defined(CONFIG_405GP) || \
1188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1190 defined(CONFIG_440)
1191 sys_info_t sys_info;
1192
1193 get_sys_info (&sys_info);
1194 val = sys_info.freqPLB;
1195 #else
1196 # error get_bus_freq() not implemented
1197 #endif
1198
1199 return val;
1200 }
1201
1202 ulong get_OPB_freq (void)
1203 {
1204 PPC4xx_SYS_INFO sys_info;
1205
1206 get_sys_info (&sys_info);
1207
1208 return sys_info.freqOPB;
1209 }