blob: fa799529d375f17598db1a2e1fc5b10cac921ce2 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
Stefan Roese2801b2d2008-03-11 15:05:50 +01002 * (C) Copyright 2000-2008
wdenkc6097192002-11-03 00:24:07 +00003 * 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 <ppc4xx.h>
27#include <asm/processor.h>
28
Wolfgang Denkd87080b2006-03-31 18:32:53 +020029DECLARE_GLOBAL_DATA_PTR;
wdenkc6097192002-11-03 00:24:07 +000030
31#define ONE_BILLION 1000000000
Marian Balakowicz6c5879f2006-06-30 16:30:46 +020032#ifdef DEBUG
33#define DEBUGF(fmt,args...) printf(fmt ,##args)
34#else
35#define DEBUGF(fmt,args...)
36#endif
wdenkc6097192002-11-03 00:24:07 +000037
Stefan Roese2801b2d2008-03-11 15:05:50 +010038#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
39
wdenkc6097192002-11-03 00:24:07 +000040#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
41
Stefan Roese087dfdb2007-10-21 08:12:41 +020042void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
wdenkc6097192002-11-03 00:24:07 +000043{
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 (pllmd);
54
55 /*
56 * Read Pin Strapping register
57 */
58 psr = mfdcr (strap);
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 */
stroesebaa3d522003-04-04 16:00:33 +000096 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
wdenkc6097192002-11-03 00:24:07 +000097 /*
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
stroeseb39392a2004-12-16 18:13:53 +0000141 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);
wdenkc6097192002-11-03 00:24:07 +0000145 } 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 {
stroeseb39392a2004-12-16 18:13:53 +0000157 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;
wdenkc6097192002-11-03 00:24:07 +0000165 }
166 }
Stefan Roesefa8aea22007-10-22 07:33:52 +0200167
168 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000169}
170
171
172/********************************************
173 * get_OPB_freq
174 * return OPB bus freq in Hz
175 *********************************************/
176ulong get_OPB_freq (void)
177{
178 ulong val = 0;
179
Stefan Roese087dfdb2007-10-21 08:12:41 +0200180 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000181
182 get_sys_info (&sys_info);
183 val = sys_info.freqPLB / sys_info.pllOpbDiv;
184
185 return val;
186}
187
188
189/********************************************
190 * get_PCI_freq
191 * return PCI bus freq in Hz
192 *********************************************/
193ulong get_PCI_freq (void)
194{
195 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200196 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000197
198 get_sys_info (&sys_info);
199 val = sys_info.freqPLB / sys_info.pllPciDiv;
200 return val;
201}
202
203
204#elif defined(CONFIG_440)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200205
Stefan Roese2801b2d2008-03-11 15:05:50 +0100206#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
207static u8 pll_fwdv_multi_bits[] = {
208 /* values for: 1 - 16 */
209 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
210 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
211};
212
213u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
214{
215 u32 index;
216
217 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
218 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
219 return index + 1;
220
221 return 0;
222}
223
224static u8 pll_fbdv_multi_bits[] = {
225 /* values for: 1 - 100 */
226 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
227 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
228 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
229 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
230 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
231 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
232 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
233 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
234 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
235 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
236 /* values for: 101 - 200 */
237 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
238 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
239 0x20, 0xc0, 0x01, 0x83, 0x77, 0xff, 0x1f, 0xbf, 0x7f, 0xfe,
240 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
241 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
242 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
243 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
244 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
245 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
246 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
247 /* values for: 201 - 255 */
248 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
249 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
250 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
251 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
252 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
253 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
254};
255
256u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
257{
258 u32 index;
259
260 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
261 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
262 return index + 1;
263
264 return 0;
265}
266
267/*
268 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
269 * with latest EAS
270 */
271void get_sys_info (sys_info_t * sysInfo)
272{
273 unsigned long strp0;
274 unsigned long strp1;
275 unsigned long temp;
276 unsigned long m;
277 unsigned long plbedv0;
278
279 /* Extract configured divisors */
280 mfsdr(sdr_sdstp0, strp0);
281 mfsdr(sdr_sdstp1, strp1);
282
283 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
284 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
285
286 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
287 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
288
289 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
290 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
291
292 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
293 sysInfo->pllOpbDiv = temp ? temp : 4;
294
295 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
296 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
297 sysInfo->pllExtBusDiv = temp ? temp : 4;
298
299 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
300 plbedv0 = temp ? temp: 8;
301
302 /* Calculate 'M' based on feedback source */
303 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
304 if (temp == 0) {
305 /* PLL internal feedback */
306 m = sysInfo->pllFbkDiv;
307 } else {
308 /* PLL PerClk feedback */
309 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
310 sysInfo->pllExtBusDiv;
311 }
312
313 /* Now calculate the individual clocks */
314 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
315 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
316 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
317 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
318 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
319 sysInfo->freqDDR = sysInfo->freqPLB;
320 sysInfo->freqUART = sysInfo->freqPLB;
321
322 return;
323}
324
325#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200326 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200327void get_sys_info (sys_info_t *sysInfo)
328{
329 unsigned long temp;
330 unsigned long reg;
331 unsigned long lfdiv;
332 unsigned long m;
333 unsigned long prbdv0;
334 /*
335 WARNING: ASSUMES the following:
336 ENG=1
337 PRADV0=1
338 PRBDV0=1
339 */
340
341 /* Decode CPR0_PLLD0 for divisors */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200342 mfcpr(clk_plld, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200343 temp = (reg & PLLD_FWDVA_MASK) >> 16;
344 sysInfo->pllFwdDivA = temp ? temp : 16;
345 temp = (reg & PLLD_FWDVB_MASK) >> 8;
346 sysInfo->pllFwdDivB = temp ? temp: 8 ;
347 temp = (reg & PLLD_FBDV_MASK) >> 24;
348 sysInfo->pllFbkDiv = temp ? temp : 32;
349 lfdiv = reg & PLLD_LFBDV_MASK;
350
Stefan Roese087dfdb2007-10-21 08:12:41 +0200351 mfcpr(clk_opbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200352 temp = (reg & OPBDDV_MASK) >> 24;
353 sysInfo->pllOpbDiv = temp ? temp : 4;
354
Stefan Roese087dfdb2007-10-21 08:12:41 +0200355 mfcpr(clk_perd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200356 temp = (reg & PERDV_MASK) >> 24;
357 sysInfo->pllExtBusDiv = temp ? temp : 8;
358
Stefan Roese087dfdb2007-10-21 08:12:41 +0200359 mfcpr(clk_primbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200360 temp = (reg & PRBDV_MASK) >> 24;
361 prbdv0 = temp ? temp : 8;
362
Stefan Roese087dfdb2007-10-21 08:12:41 +0200363 mfcpr(clk_spcid, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200364 temp = (reg & SPCID_MASK) >> 24;
365 sysInfo->pllPciDiv = temp ? temp : 4;
366
367 /* Calculate 'M' based on feedback source */
368 mfsdr(sdr_sdstp0, reg);
369 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
370 if (temp == 0) { /* PLL output */
371 /* Figure which pll to use */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200372 mfcpr(clk_pllc, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200373 temp = (reg & PLLC_SRC_MASK) >> 29;
374 if (!temp) /* PLLOUTA */
375 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
376 else /* PLLOUTB */
377 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
378 }
379 else if (temp == 1) /* CPU output */
380 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
381 else /* PerClk */
382 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
383
384 /* Now calculate the individual clocks */
385 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
386 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
387 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
388 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200389 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200390 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200391 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200392
393 /* Figure which timer source to use */
394 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
395 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
396 if (CONFIG_SYS_CLK_FREQ > temp)
397 sysInfo->freqTmrClk = temp;
398 else
399 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
400 }
401 else /* Internal clock */
402 sysInfo->freqTmrClk = sysInfo->freqProcessor;
403}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200404
Stefan Roesec157d8e2005-08-01 16:41:48 +0200405/********************************************
406 * get_PCI_freq
407 * return PCI bus freq in Hz
408 *********************************************/
409ulong get_PCI_freq (void)
410{
411 sys_info_t sys_info;
412 get_sys_info (&sys_info);
413 return sys_info.freqPCI;
414}
415
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200416#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
wdenkc6097192002-11-03 00:24:07 +0000417void get_sys_info (sys_info_t * sysInfo)
418{
419 unsigned long strp0;
420 unsigned long temp;
421 unsigned long m;
422
423 /* Extract configured divisors */
424 strp0 = mfdcr( cpc0_strp0 );
425 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
426 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
427 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
428 sysInfo->pllFbkDiv = temp ? temp : 16;
429 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
430 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
431
432 /* Calculate 'M' based on feedback source */
433 if( strp0 & PLLSYS0_EXTSL_MASK )
434 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
435 else
436 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
437
438 /* Now calculate the individual clocks */
439 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
440 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
441 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200442 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
443 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000444 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200445 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200446 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000447}
wdenkba56f622004-02-06 23:19:44 +0000448#else
449void get_sys_info (sys_info_t * sysInfo)
450{
451 unsigned long strp0;
452 unsigned long strp1;
453 unsigned long temp;
454 unsigned long temp1;
455 unsigned long lfdiv;
456 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000457 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000458
Stefan Roese4745aca2007-02-20 10:57:08 +0100459#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200460 unsigned long sys_freq;
461 unsigned long sys_per=0;
462 unsigned long msr;
463 unsigned long pci_clock_per;
464 unsigned long sdr_ddrpll;
465
466 /*-------------------------------------------------------------------------+
467 | Get the system clock period.
468 +-------------------------------------------------------------------------*/
469 sys_per = determine_sysper();
470
471 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
472
473 /*-------------------------------------------------------------------------+
474 | Calculate the system clock speed from the period.
475 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100476 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200477#endif
478
wdenkba56f622004-02-06 23:19:44 +0000479 /* Extract configured divisors */
480 mfsdr( sdr_sdstp0,strp0 );
481 mfsdr( sdr_sdstp1,strp1 );
482
483 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
484 sysInfo->pllFwdDivA = temp ? temp : 16 ;
485 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
486 sysInfo->pllFwdDivB = temp ? temp: 8 ;
487 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
488 sysInfo->pllFbkDiv = temp ? temp : 32;
489 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
490 sysInfo->pllOpbDiv = temp ? temp : 4;
491 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
492 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000493 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000494
495 /* Calculate 'M' based on feedback source */
496 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
497 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
498 lfdiv = temp1 ? temp1 : 64;
499 if (temp == 0) { /* PLL output */
500 /* Figure which pll to use */
501 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
502 if (!temp)
503 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
504 else
505 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
506 }
507 else if (temp == 1) /* CPU output */
508 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
509 else /* PerClk */
510 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
511
512 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100513#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200514 sysInfo->freqVCOMhz = (m * sys_freq) ;
515#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100516 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200517#endif
wdenkba56f622004-02-06 23:19:44 +0000518 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000519 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000520 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200521 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000522
Stefan Roese4745aca2007-02-20 10:57:08 +0100523#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200524 /* Determine PCI Clock Period */
525 pci_clock_per = determine_pci_clock_per();
526 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
527 mfsdr(sdr_ddr0, sdr_ddrpll);
528 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
529#endif
530
Stefan Roesefa8aea22007-10-22 07:33:52 +0200531 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200532}
533
534#endif
535
Stefan Roese4745aca2007-02-20 10:57:08 +0100536#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200537unsigned long determine_sysper(void)
538{
539 unsigned int fpga_clocking_reg;
540 unsigned int master_clock_selection;
541 unsigned long master_clock_per = 0;
542 unsigned long fb_div_selection;
543 unsigned int vco_div_reg_value;
544 unsigned long vco_div_selection;
545 unsigned long sys_per = 0;
546 int extClkVal;
547
548 /*-------------------------------------------------------------------------+
549 | Read FPGA reg 0 and reg 1 to get FPGA reg information
550 +-------------------------------------------------------------------------*/
551 fpga_clocking_reg = in16(FPGA_REG16);
552
553
554 /* Determine Master Clock Source Selection */
555 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
556
557 switch(master_clock_selection) {
558 case FPGA_REG16_MASTER_CLK_66_66:
559 master_clock_per = PERIOD_66_66MHZ;
560 break;
561 case FPGA_REG16_MASTER_CLK_50:
562 master_clock_per = PERIOD_50_00MHZ;
563 break;
564 case FPGA_REG16_MASTER_CLK_33_33:
565 master_clock_per = PERIOD_33_33MHZ;
566 break;
567 case FPGA_REG16_MASTER_CLK_25:
568 master_clock_per = PERIOD_25_00MHZ;
569 break;
570 case FPGA_REG16_MASTER_CLK_EXT:
571 if ((extClkVal==EXTCLK_33_33)
572 && (extClkVal==EXTCLK_50)
573 && (extClkVal==EXTCLK_66_66)
574 && (extClkVal==EXTCLK_83)) {
575 /* calculate master clock period from external clock value */
576 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
577 } else {
578 /* Unsupported */
579 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
580 hang();
581 }
582 break;
583 default:
584 /* Unsupported */
585 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
586 hang();
587 break;
588 }
589
590 /* Determine FB divisors values */
591 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
592 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
593 fb_div_selection = FPGA_FB_DIV_6;
594 else
595 fb_div_selection = FPGA_FB_DIV_12;
596 } else {
597 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
598 fb_div_selection = FPGA_FB_DIV_10;
599 else
600 fb_div_selection = FPGA_FB_DIV_20;
601 }
602
603 /* Determine VCO divisors values */
604 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
605
606 switch(vco_div_reg_value) {
607 case FPGA_REG16_VCO_DIV_4:
608 vco_div_selection = FPGA_VCO_DIV_4;
609 break;
610 case FPGA_REG16_VCO_DIV_6:
611 vco_div_selection = FPGA_VCO_DIV_6;
612 break;
613 case FPGA_REG16_VCO_DIV_8:
614 vco_div_selection = FPGA_VCO_DIV_8;
615 break;
616 case FPGA_REG16_VCO_DIV_10:
617 default:
618 vco_div_selection = FPGA_VCO_DIV_10;
619 break;
620 }
621
622 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
623 switch(master_clock_per) {
624 case PERIOD_25_00MHZ:
625 if (fb_div_selection == FPGA_FB_DIV_12) {
626 if (vco_div_selection == FPGA_VCO_DIV_4)
627 sys_per = PERIOD_75_00MHZ;
628 if (vco_div_selection == FPGA_VCO_DIV_6)
629 sys_per = PERIOD_50_00MHZ;
630 }
631 break;
632 case PERIOD_33_33MHZ:
633 if (fb_div_selection == FPGA_FB_DIV_6) {
634 if (vco_div_selection == FPGA_VCO_DIV_4)
635 sys_per = PERIOD_50_00MHZ;
636 if (vco_div_selection == FPGA_VCO_DIV_6)
637 sys_per = PERIOD_33_33MHZ;
638 }
639 if (fb_div_selection == FPGA_FB_DIV_10) {
640 if (vco_div_selection == FPGA_VCO_DIV_4)
641 sys_per = PERIOD_83_33MHZ;
642 if (vco_div_selection == FPGA_VCO_DIV_10)
643 sys_per = PERIOD_33_33MHZ;
644 }
645 if (fb_div_selection == FPGA_FB_DIV_12) {
646 if (vco_div_selection == FPGA_VCO_DIV_4)
647 sys_per = PERIOD_100_00MHZ;
648 if (vco_div_selection == FPGA_VCO_DIV_6)
649 sys_per = PERIOD_66_66MHZ;
650 if (vco_div_selection == FPGA_VCO_DIV_8)
651 sys_per = PERIOD_50_00MHZ;
652 }
653 break;
654 case PERIOD_50_00MHZ:
655 if (fb_div_selection == FPGA_FB_DIV_6) {
656 if (vco_div_selection == FPGA_VCO_DIV_4)
657 sys_per = PERIOD_75_00MHZ;
658 if (vco_div_selection == FPGA_VCO_DIV_6)
659 sys_per = PERIOD_50_00MHZ;
660 }
661 if (fb_div_selection == FPGA_FB_DIV_10) {
662 if (vco_div_selection == FPGA_VCO_DIV_6)
663 sys_per = PERIOD_83_33MHZ;
664 if (vco_div_selection == FPGA_VCO_DIV_10)
665 sys_per = PERIOD_50_00MHZ;
666 }
667 if (fb_div_selection == FPGA_FB_DIV_12) {
668 if (vco_div_selection == FPGA_VCO_DIV_6)
669 sys_per = PERIOD_100_00MHZ;
670 if (vco_div_selection == FPGA_VCO_DIV_8)
671 sys_per = PERIOD_75_00MHZ;
672 }
673 break;
674 case PERIOD_66_66MHZ:
675 if (fb_div_selection == FPGA_FB_DIV_6) {
676 if (vco_div_selection == FPGA_VCO_DIV_4)
677 sys_per = PERIOD_100_00MHZ;
678 if (vco_div_selection == FPGA_VCO_DIV_6)
679 sys_per = PERIOD_66_66MHZ;
680 if (vco_div_selection == FPGA_VCO_DIV_8)
681 sys_per = PERIOD_50_00MHZ;
682 }
683 if (fb_div_selection == FPGA_FB_DIV_10) {
684 if (vco_div_selection == FPGA_VCO_DIV_8)
685 sys_per = PERIOD_83_33MHZ;
686 if (vco_div_selection == FPGA_VCO_DIV_10)
687 sys_per = PERIOD_66_66MHZ;
688 }
689 if (fb_div_selection == FPGA_FB_DIV_12) {
690 if (vco_div_selection == FPGA_VCO_DIV_8)
691 sys_per = PERIOD_100_00MHZ;
692 }
693 break;
694 default:
695 break;
696 }
697
698 if (sys_per == 0) {
699 /* Other combinations are not supported */
700 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
701 hang();
702 }
703 } else {
704 /* calcul system clock without cheking */
705 /* if engineering option clock no check is selected */
706 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
707 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
708 }
709
710 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200711}
712
713/*-------------------------------------------------------------------------+
714| determine_pci_clock_per.
715+-------------------------------------------------------------------------*/
716unsigned long determine_pci_clock_per(void)
717{
718 unsigned long pci_clock_selection, pci_period;
719
720 /*-------------------------------------------------------------------------+
721 | Read FPGA reg 6 to get PCI 0 FPGA reg information
722 +-------------------------------------------------------------------------*/
723 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
724
725
726 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
727
728 switch (pci_clock_selection) {
729 case FPGA_REG16_PCI0_CLK_133_33:
730 pci_period = PERIOD_133_33MHZ;
731 break;
732 case FPGA_REG16_PCI0_CLK_100:
733 pci_period = PERIOD_100_00MHZ;
734 break;
735 case FPGA_REG16_PCI0_CLK_66_66:
736 pci_period = PERIOD_66_66MHZ;
737 break;
738 default:
739 pci_period = PERIOD_33_33MHZ;;
740 break;
741 }
742
743 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000744}
745#endif
wdenkc6097192002-11-03 00:24:07 +0000746
747ulong get_OPB_freq (void)
748{
749
750 sys_info_t sys_info;
751 get_sys_info (&sys_info);
752 return sys_info.freqOPB;
753}
754
wdenk028ab6b2004-02-23 23:54:43 +0000755#elif defined(CONFIG_XILINX_ML300)
756extern void get_sys_info (sys_info_t * sysInfo);
757extern ulong get_PCI_freq (void);
758
Wolfgang Denk7521af12005-10-09 01:04:33 +0200759#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200760void get_sys_info (sys_info_t * sysInfo)
761{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200762 sysInfo->freqProcessor = 240 * 1000 * 1000;
763 sysInfo->freqPLB = 80 * 1000 * 1000;
764 sysInfo->freqPCI = 33 * 1000 * 1000;
765}
766
wdenkc6097192002-11-03 00:24:07 +0000767#elif defined(CONFIG_405)
768
Stefan Roesefa8aea22007-10-22 07:33:52 +0200769void get_sys_info (sys_info_t * sysInfo)
770{
wdenkc6097192002-11-03 00:24:07 +0000771 sysInfo->freqVCOMhz=3125000;
772 sysInfo->freqProcessor=12*1000*1000;
773 sysInfo->freqPLB=50*1000*1000;
774 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000775}
776
stroeseb867d702003-05-23 11:18:02 +0000777#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200778void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000779{
780 unsigned long pllmr0;
781 unsigned long pllmr1;
782 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
783 unsigned long m;
784 unsigned long pllmr0_ccdv;
785
786 /*
787 * Read PLL Mode registers
788 */
789 pllmr0 = mfdcr (cpc0_pllmr0);
790 pllmr1 = mfdcr (cpc0_pllmr1);
791
792 /*
793 * Determine forward divider A
794 */
795 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
796
797 /*
798 * Determine forward divider B (should be equal to A)
799 */
800 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
801
802 /*
803 * Determine FBK_DIV.
804 */
805 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200806 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000807 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000808
809 /*
810 * Determine PLB_DIV.
811 */
812 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
813
814 /*
815 * Determine PCI_DIV.
816 */
817 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
818
819 /*
820 * Determine EXTBUS_DIV.
821 */
822 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
823
824 /*
825 * Determine OPB_DIV.
826 */
827 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
828
829 /*
830 * Determine the M factor
831 */
832 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
833
834 /*
835 * Determine VCO clock frequency
836 */
stroeseb39392a2004-12-16 18:13:53 +0000837 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
838 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000839
840 /*
841 * Determine CPU clock frequency
842 */
843 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
844 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000845 /*
846 * This is true if FWDVA == FWDVB:
847 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
848 * / pllmr0_ccdv;
849 */
850 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
851 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000852 } else {
853 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
854 }
855
856 /*
857 * Determine PLB clock frequency
858 */
859 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200860
861 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200862
863 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000864}
865
866
867/********************************************
868 * get_OPB_freq
869 * return OPB bus freq in Hz
870 *********************************************/
871ulong get_OPB_freq (void)
872{
873 ulong val = 0;
874
Stefan Roese087dfdb2007-10-21 08:12:41 +0200875 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000876
877 get_sys_info (&sys_info);
878 val = sys_info.freqPLB / sys_info.pllOpbDiv;
879
880 return val;
881}
882
883
884/********************************************
885 * get_PCI_freq
886 * return PCI bus freq in Hz
887 *********************************************/
888ulong get_PCI_freq (void)
889{
890 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200891 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000892
893 get_sys_info (&sys_info);
894 val = sys_info.freqPLB / sys_info.pllPciDiv;
895 return val;
896}
897
Stefan Roesee01bd212007-03-21 13:38:59 +0100898#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200899void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100900{
901 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200902 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100903 unsigned long cpr_primad;
904 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
905 unsigned long primad_cpudv;
906 unsigned long m;
907
908 /*
909 * Read PLL Mode registers
910 */
911 mfcpr(cprplld, cpr_plld);
Stefan Roese273db7e2007-08-13 09:05:33 +0200912 mfcpr(cprpllc, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100913
914 /*
915 * Determine forward divider A
916 */
917 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
918
919 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200920 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100921 */
922 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200923 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100924 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100925
926 /*
927 * Determine FBK_DIV.
928 */
929 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200930 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100931 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100932
933 /*
934 * Read CPR_PRIMAD register
935 */
936 mfcpr(cprprimad, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200937
Stefan Roesee01bd212007-03-21 13:38:59 +0100938 /*
939 * Determine PLB_DIV.
940 */
941 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200942 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100943 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100944
945 /*
946 * Determine EXTBUS_DIV.
947 */
948 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200949 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100950 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100951
952 /*
953 * Determine OPB_DIV.
954 */
955 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200956 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100957 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100958
959 /*
960 * Determine the M factor
961 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200962 if (cpr_pllc & PLLC_SRC_MASK)
963 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
964 else
965 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100966
967 /*
968 * Determine VCO clock frequency
969 */
970 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
971 (unsigned long long)sysClkPeriodPs;
972
973 /*
974 * Determine CPU clock frequency
975 */
976 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200977 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100978 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100979
Stefan Roese273db7e2007-08-13 09:05:33 +0200980 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
981 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100982
983 /*
984 * Determine PLB clock frequency
985 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200986 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
987 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200988
989 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
990 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200991
992 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roesee01bd212007-03-21 13:38:59 +0100993}
994
995/********************************************
996 * get_OPB_freq
997 * return OPB bus freq in Hz
998 *********************************************/
999ulong get_OPB_freq (void)
1000{
1001 ulong val = 0;
1002
Stefan Roese087dfdb2007-10-21 08:12:41 +02001003 PPC4xx_SYS_INFO sys_info;
Stefan Roesee01bd212007-03-21 13:38:59 +01001004
1005 get_sys_info (&sys_info);
1006 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1007
1008 return val;
1009}
1010
Stefan Roesedbbd1252007-10-05 17:10:59 +02001011#elif defined(CONFIG_405EX)
1012
1013/*
1014 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1015 * We need the specs!!!!
1016 */
1017static unsigned char get_fbdv(unsigned char index)
1018{
1019 unsigned char ret = 0;
1020 /* This is table should be 256 bytes.
1021 * Only take first 52 values.
1022 */
1023 unsigned char fbdv_tb[] = {
1024 0x00, 0xff, 0x7f, 0xfd,
1025 0x7a, 0xf5, 0x6a, 0xd5,
1026 0x2a, 0xd4, 0x29, 0xd3,
1027 0x26, 0xcc, 0x19, 0xb3,
1028 0x67, 0xce, 0x1d, 0xbb,
1029 0x77, 0xee, 0x5d, 0xba,
1030 0x74, 0xe9, 0x52, 0xa5,
1031 0x4b, 0x96, 0x2c, 0xd8,
1032 0x31, 0xe3, 0x46, 0x8d,
1033 0x1b, 0xb7, 0x6f, 0xde,
1034 0x3d, 0xfb, 0x76, 0xed,
1035 0x5a, 0xb5, 0x6b, 0xd6,
1036 0x2d, 0xdb, 0x36, 0xec,
1037
1038 };
1039
1040 if ((index & 0x7f) == 0)
1041 return 1;
1042 while (ret < sizeof (fbdv_tb)) {
1043 if (fbdv_tb[ret] == index)
1044 break;
1045 ret++;
1046 }
1047 ret++;
1048
1049 return ret;
1050}
1051
1052#define PLL_FBK_PLL_LOCAL 0
1053#define PLL_FBK_CPU 1
1054#define PLL_FBK_PERCLK 5
1055
1056void get_sys_info (sys_info_t * sysInfo)
1057{
1058 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1059 unsigned long m = 1;
1060 unsigned int tmp;
1061 unsigned char fwdva[16] = {
1062 1, 2, 14, 9, 4, 11, 16, 13,
1063 12, 5, 6, 15, 10, 7, 8, 3,
1064 };
1065 unsigned char sel, cpudv0, plb2xDiv;
1066
1067 mfcpr(cpr0_plld, tmp);
1068
1069 /*
1070 * Determine forward divider A
1071 */
1072 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1073
1074 /*
1075 * Determine FBK_DIV.
1076 */
1077 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1078
1079 /*
1080 * Determine PLBDV0
1081 */
1082 sysInfo->pllPlbDiv = 2;
1083
1084 /*
1085 * Determine PERDV0
1086 */
1087 mfcpr(cpr0_perd, tmp);
1088 tmp = (tmp >> 24) & 0x03;
1089 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1090
1091 /*
1092 * Determine OPBDV0
1093 */
1094 mfcpr(cpr0_opbd, tmp);
1095 tmp = (tmp >> 24) & 0x03;
1096 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1097
1098 /* Determine PLB2XDV0 */
1099 mfcpr(cpr0_plbd, tmp);
1100 tmp = (tmp >> 16) & 0x07;
1101 plb2xDiv = (tmp == 0) ? 8 : tmp;
1102
1103 /* Determine CPUDV0 */
1104 mfcpr(cpr0_cpud, tmp);
1105 tmp = (tmp >> 24) & 0x07;
1106 cpudv0 = (tmp == 0) ? 8 : tmp;
1107
1108 /* Determine SEL(5:7) in CPR0_PLLC */
1109 mfcpr(cpr0_pllc, tmp);
1110 sel = (tmp >> 24) & 0x07;
1111
1112 /*
1113 * Determine the M factor
1114 * PLL local: M = FBDV
1115 * CPU clock: M = FBDV * FWDVA * CPUDV0
1116 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1117 *
1118 */
1119 switch (sel) {
1120 case PLL_FBK_CPU:
1121 m = sysInfo->pllFwdDiv * cpudv0;
1122 break;
1123 case PLL_FBK_PERCLK:
1124 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1125 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1126 break;
1127 case PLL_FBK_PLL_LOCAL:
1128 break;
1129 default:
1130 printf("%s unknown m\n", __FUNCTION__);
1131 return;
1132
1133 }
1134 m *= sysInfo->pllFbkDiv;
1135
1136 /*
1137 * Determine VCO clock frequency
1138 */
1139 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1140 (unsigned long long)sysClkPeriodPs;
1141
1142 /*
1143 * Determine CPU clock frequency
1144 */
1145 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1146
1147 /*
1148 * Determine PLB clock frequency, ddr1x should be the same
1149 */
1150 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1151 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1152 sysInfo->freqDDR = sysInfo->freqPLB;
1153 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001154 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001155}
1156
1157/********************************************
1158 * get_OPB_freq
1159 * return OPB bus freq in Hz
1160 *********************************************/
1161ulong get_OPB_freq (void)
1162{
1163 ulong val = 0;
1164
Stefan Roese087dfdb2007-10-21 08:12:41 +02001165 PPC4xx_SYS_INFO sys_info;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001166
1167 get_sys_info (&sys_info);
1168 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1169
1170 return val;
1171}
1172
wdenkc6097192002-11-03 00:24:07 +00001173#endif
1174
1175int get_clocks (void)
1176{
Stefan Roesee01bd212007-03-21 13:38:59 +01001177#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1178 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001179 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1180 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001181 sys_info_t sys_info;
1182
1183 get_sys_info (&sys_info);
1184 gd->cpu_clk = sys_info.freqProcessor;
1185 gd->bus_clk = sys_info.freqPLB;
1186
1187#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1188
1189#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001190 gd->cpu_clk = 66000000;
1191 gd->bus_clk = 66000000;
1192#endif
1193 return (0);
1194}
1195
1196
1197/********************************************
1198 * get_bus_freq
1199 * return PLB bus freq in Hz
1200 *********************************************/
1201ulong get_bus_freq (ulong dummy)
1202{
1203 ulong val;
1204
Stefan Roesee01bd212007-03-21 13:38:59 +01001205#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1206 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001207 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1208 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001209 sys_info_t sys_info;
1210
1211 get_sys_info (&sys_info);
1212 val = sys_info.freqPLB;
1213
1214#elif defined(CONFIG_IOP480)
1215
1216 val = 66;
1217
1218#else
1219# error get_bus_freq() not implemented
1220#endif
1221
1222 return val;
1223}