]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/powerpc/cpu/ppc4xx/speed.c
Merge branch 'master' of git://git.denx.de/u-boot-blackfin
[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_AP1000)
816 void get_sys_info (sys_info_t * sysInfo)
817 {
818 sysInfo->freqProcessor = 240 * 1000 * 1000;
819 sysInfo->freqPLB = 80 * 1000 * 1000;
820 sysInfo->freqPCI = 33 * 1000 * 1000;
821 }
822
823 #elif defined(CONFIG_405)
824
825 void get_sys_info (sys_info_t * sysInfo)
826 {
827 sysInfo->freqVCOMhz=3125000;
828 sysInfo->freqProcessor=12*1000*1000;
829 sysInfo->freqPLB=50*1000*1000;
830 sysInfo->freqPCI=66*1000*1000;
831 }
832
833 #elif defined(CONFIG_405EP)
834 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
835 {
836 unsigned long pllmr0;
837 unsigned long pllmr1;
838 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
839 unsigned long m;
840 unsigned long pllmr0_ccdv;
841
842 /*
843 * Read PLL Mode registers
844 */
845 pllmr0 = mfdcr (CPC0_PLLMR0);
846 pllmr1 = mfdcr (CPC0_PLLMR1);
847
848 /*
849 * Determine forward divider A
850 */
851 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
852
853 /*
854 * Determine forward divider B (should be equal to A)
855 */
856 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
857
858 /*
859 * Determine FBK_DIV.
860 */
861 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
862 if (sysInfo->pllFbkDiv == 0)
863 sysInfo->pllFbkDiv = 16;
864
865 /*
866 * Determine PLB_DIV.
867 */
868 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
869
870 /*
871 * Determine PCI_DIV.
872 */
873 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
874
875 /*
876 * Determine EXTBUS_DIV.
877 */
878 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
879
880 /*
881 * Determine OPB_DIV.
882 */
883 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
884
885 /*
886 * Determine the M factor
887 */
888 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
889
890 /*
891 * Determine VCO clock frequency
892 */
893 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
894 (unsigned long long)sysClkPeriodPs;
895
896 /*
897 * Determine CPU clock frequency
898 */
899 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
900 if (pllmr1 & PLLMR1_SSCS_MASK) {
901 /*
902 * This is true if FWDVA == FWDVB:
903 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
904 * / pllmr0_ccdv;
905 */
906 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
907 / sysInfo->pllFwdDiv / pllmr0_ccdv;
908 } else {
909 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
910 }
911
912 /*
913 * Determine PLB clock frequency
914 */
915 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
916
917 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
918
919 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
920
921 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
922 }
923
924
925 /********************************************
926 * get_PCI_freq
927 * return PCI bus freq in Hz
928 *********************************************/
929 ulong get_PCI_freq (void)
930 {
931 ulong val;
932 PPC4xx_SYS_INFO sys_info;
933
934 get_sys_info (&sys_info);
935 val = sys_info.freqPLB / sys_info.pllPciDiv;
936 return val;
937 }
938
939 #elif defined(CONFIG_405EZ)
940 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
941 {
942 unsigned long cpr_plld;
943 unsigned long cpr_pllc;
944 unsigned long cpr_primad;
945 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
946 unsigned long primad_cpudv;
947 unsigned long m;
948 unsigned long plloutb;
949
950 /*
951 * Read PLL Mode registers
952 */
953 mfcpr(CPR0_PLLD, cpr_plld);
954 mfcpr(CPR0_PLLC, cpr_pllc);
955
956 /*
957 * Determine forward divider A
958 */
959 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
960
961 /*
962 * Determine forward divider B
963 */
964 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
965 if (sysInfo->pllFwdDivB == 0)
966 sysInfo->pllFwdDivB = 8;
967
968 /*
969 * Determine FBK_DIV.
970 */
971 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
972 if (sysInfo->pllFbkDiv == 0)
973 sysInfo->pllFbkDiv = 256;
974
975 /*
976 * Read CPR_PRIMAD register
977 */
978 mfcpr(CPR0_PRIMAD, cpr_primad);
979
980 /*
981 * Determine PLB_DIV.
982 */
983 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
984 if (sysInfo->pllPlbDiv == 0)
985 sysInfo->pllPlbDiv = 16;
986
987 /*
988 * Determine EXTBUS_DIV.
989 */
990 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
991 if (sysInfo->pllExtBusDiv == 0)
992 sysInfo->pllExtBusDiv = 16;
993
994 /*
995 * Determine OPB_DIV.
996 */
997 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
998 if (sysInfo->pllOpbDiv == 0)
999 sysInfo->pllOpbDiv = 16;
1000
1001 /*
1002 * Determine the M factor
1003 */
1004 if (cpr_pllc & PLLC_SRC_MASK)
1005 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
1006 else
1007 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
1008
1009 /*
1010 * Determine VCO clock frequency
1011 */
1012 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1013 (unsigned long long)sysClkPeriodPs;
1014
1015 /*
1016 * Determine CPU clock frequency
1017 */
1018 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
1019 if (primad_cpudv == 0)
1020 primad_cpudv = 16;
1021
1022 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1023 sysInfo->pllFwdDiv / primad_cpudv;
1024
1025 /*
1026 * Determine PLB clock frequency
1027 */
1028 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1029 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
1030
1031 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1032 sysInfo->pllOpbDiv;
1033
1034 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1035 sysInfo->pllExtBusDiv;
1036
1037 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1038 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1039 sysInfo->pllFwdDivB);
1040 sysInfo->freqUART = plloutb;
1041 }
1042
1043 #elif defined(CONFIG_405EX)
1044
1045 /*
1046 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1047 * We need the specs!!!!
1048 */
1049 static unsigned char get_fbdv(unsigned char index)
1050 {
1051 unsigned char ret = 0;
1052 /* This is table should be 256 bytes.
1053 * Only take first 52 values.
1054 */
1055 unsigned char fbdv_tb[] = {
1056 0x00, 0xff, 0x7f, 0xfd,
1057 0x7a, 0xf5, 0x6a, 0xd5,
1058 0x2a, 0xd4, 0x29, 0xd3,
1059 0x26, 0xcc, 0x19, 0xb3,
1060 0x67, 0xce, 0x1d, 0xbb,
1061 0x77, 0xee, 0x5d, 0xba,
1062 0x74, 0xe9, 0x52, 0xa5,
1063 0x4b, 0x96, 0x2c, 0xd8,
1064 0x31, 0xe3, 0x46, 0x8d,
1065 0x1b, 0xb7, 0x6f, 0xde,
1066 0x3d, 0xfb, 0x76, 0xed,
1067 0x5a, 0xb5, 0x6b, 0xd6,
1068 0x2d, 0xdb, 0x36, 0xec,
1069
1070 };
1071
1072 if ((index & 0x7f) == 0)
1073 return 1;
1074 while (ret < sizeof (fbdv_tb)) {
1075 if (fbdv_tb[ret] == index)
1076 break;
1077 ret++;
1078 }
1079 ret++;
1080
1081 return ret;
1082 }
1083
1084 #define PLL_FBK_PLL_LOCAL 0
1085 #define PLL_FBK_CPU 1
1086 #define PLL_FBK_PERCLK 5
1087
1088 void get_sys_info (sys_info_t * sysInfo)
1089 {
1090 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1091 unsigned long m = 1;
1092 unsigned int tmp;
1093 unsigned char fwdva[16] = {
1094 1, 2, 14, 9, 4, 11, 16, 13,
1095 12, 5, 6, 15, 10, 7, 8, 3,
1096 };
1097 unsigned char sel, cpudv0, plb2xDiv;
1098
1099 mfcpr(CPR0_PLLD, tmp);
1100
1101 /*
1102 * Determine forward divider A
1103 */
1104 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1105
1106 /*
1107 * Determine FBK_DIV.
1108 */
1109 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1110
1111 /*
1112 * Determine PLBDV0
1113 */
1114 sysInfo->pllPlbDiv = 2;
1115
1116 /*
1117 * Determine PERDV0
1118 */
1119 mfcpr(CPR0_PERD, tmp);
1120 tmp = (tmp >> 24) & 0x03;
1121 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1122
1123 /*
1124 * Determine OPBDV0
1125 */
1126 mfcpr(CPR0_OPBD0, tmp);
1127 tmp = (tmp >> 24) & 0x03;
1128 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1129
1130 /* Determine PLB2XDV0 */
1131 mfcpr(CPR0_PLBD, tmp);
1132 tmp = (tmp >> 16) & 0x07;
1133 plb2xDiv = (tmp == 0) ? 8 : tmp;
1134
1135 /* Determine CPUDV0 */
1136 mfcpr(CPR0_CPUD, tmp);
1137 tmp = (tmp >> 24) & 0x07;
1138 cpudv0 = (tmp == 0) ? 8 : tmp;
1139
1140 /* Determine SEL(5:7) in CPR0_PLLC */
1141 mfcpr(CPR0_PLLC, tmp);
1142 sel = (tmp >> 24) & 0x07;
1143
1144 /*
1145 * Determine the M factor
1146 * PLL local: M = FBDV
1147 * CPU clock: M = FBDV * FWDVA * CPUDV0
1148 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1149 *
1150 */
1151 switch (sel) {
1152 case PLL_FBK_CPU:
1153 m = sysInfo->pllFwdDiv * cpudv0;
1154 break;
1155 case PLL_FBK_PERCLK:
1156 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1157 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1158 break;
1159 case PLL_FBK_PLL_LOCAL:
1160 break;
1161 default:
1162 printf("%s unknown m\n", __FUNCTION__);
1163 return;
1164
1165 }
1166 m *= sysInfo->pllFbkDiv;
1167
1168 /*
1169 * Determine VCO clock frequency
1170 */
1171 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1172 (unsigned long long)sysClkPeriodPs;
1173
1174 /*
1175 * Determine CPU clock frequency
1176 */
1177 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1178
1179 /*
1180 * Determine PLB clock frequency, ddr1x should be the same
1181 */
1182 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1183 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1184 sysInfo->freqDDR = sysInfo->freqPLB;
1185 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1186 sysInfo->freqUART = sysInfo->freqPLB;
1187 }
1188
1189 #endif
1190
1191 int get_clocks (void)
1192 {
1193 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1194 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1195 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1196 defined(CONFIG_440)
1197 sys_info_t sys_info;
1198
1199 get_sys_info (&sys_info);
1200 gd->cpu_clk = sys_info.freqProcessor;
1201 gd->bus_clk = sys_info.freqPLB;
1202
1203 #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1204
1205 #ifdef CONFIG_IOP480
1206 gd->cpu_clk = 66000000;
1207 gd->bus_clk = 66000000;
1208 #endif
1209 return (0);
1210 }
1211
1212
1213 /********************************************
1214 * get_bus_freq
1215 * return PLB bus freq in Hz
1216 *********************************************/
1217 ulong get_bus_freq (ulong dummy)
1218 {
1219 ulong val;
1220
1221 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1222 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1223 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1224 defined(CONFIG_440)
1225 sys_info_t sys_info;
1226
1227 get_sys_info (&sys_info);
1228 val = sys_info.freqPLB;
1229
1230 #elif defined(CONFIG_IOP480)
1231
1232 val = 66;
1233
1234 #else
1235 # error get_bus_freq() not implemented
1236 #endif
1237
1238 return val;
1239 }
1240
1241 #if !defined(CONFIG_IOP480)
1242 ulong get_OPB_freq (void)
1243 {
1244 PPC4xx_SYS_INFO sys_info;
1245
1246 get_sys_info (&sys_info);
1247
1248 return sys_info.freqOPB;
1249 }
1250 #endif