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