blob: c0a5824a63a7e9af8dcacd4a6acef3ac7a52d3ea [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
Wolfgang Denk8ed44d92008-10-19 02:35:50 +0200151 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
wdenkc6097192002-11-03 00:24:07 +0000152 */
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
Matthias Fuchse1d09682008-04-18 17:24:32 +0200168 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
169
Stefan Roesefa8aea22007-10-22 07:33:52 +0200170 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000171}
172
173
174/********************************************
175 * get_OPB_freq
176 * return OPB bus freq in Hz
177 *********************************************/
178ulong get_OPB_freq (void)
179{
180 ulong val = 0;
181
Stefan Roese087dfdb2007-10-21 08:12:41 +0200182 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000183
184 get_sys_info (&sys_info);
185 val = sys_info.freqPLB / sys_info.pllOpbDiv;
186
187 return val;
188}
189
190
191/********************************************
192 * get_PCI_freq
193 * return PCI bus freq in Hz
194 *********************************************/
195ulong get_PCI_freq (void)
196{
197 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200198 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000199
200 get_sys_info (&sys_info);
201 val = sys_info.freqPLB / sys_info.pllPciDiv;
202 return val;
203}
204
205
206#elif defined(CONFIG_440)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200207
Feng Kan7d307932008-07-08 22:47:31 -0700208#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
209 defined(CONFIG_460SX)
Stefan Roese2801b2d2008-03-11 15:05:50 +0100210static u8 pll_fwdv_multi_bits[] = {
211 /* values for: 1 - 16 */
212 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
213 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
214};
215
216u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
217{
218 u32 index;
219
220 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
221 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
222 return index + 1;
223
224 return 0;
225}
226
227static u8 pll_fbdv_multi_bits[] = {
228 /* values for: 1 - 100 */
229 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
230 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
231 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
232 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
233 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
234 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
235 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
236 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
237 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
238 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
239 /* values for: 101 - 200 */
240 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
241 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchellb9bbefc2008-05-07 09:00:23 -0700242 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roese2801b2d2008-03-11 15:05:50 +0100243 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
244 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
245 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
246 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
247 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
248 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
249 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
250 /* values for: 201 - 255 */
251 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
252 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
253 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
254 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
255 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
256 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
257};
258
259u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
260{
261 u32 index;
262
263 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
264 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
265 return index + 1;
266
267 return 0;
268}
269
270/*
271 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
272 * with latest EAS
273 */
274void get_sys_info (sys_info_t * sysInfo)
275{
276 unsigned long strp0;
277 unsigned long strp1;
278 unsigned long temp;
279 unsigned long m;
280 unsigned long plbedv0;
281
282 /* Extract configured divisors */
283 mfsdr(sdr_sdstp0, strp0);
284 mfsdr(sdr_sdstp1, strp1);
285
286 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
287 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
288
289 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
290 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
291
292 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
293 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
294
295 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
296 sysInfo->pllOpbDiv = temp ? temp : 4;
297
298 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
299 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
300 sysInfo->pllExtBusDiv = temp ? temp : 4;
301
302 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
303 plbedv0 = temp ? temp: 8;
304
305 /* Calculate 'M' based on feedback source */
306 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
307 if (temp == 0) {
308 /* PLL internal feedback */
309 m = sysInfo->pllFbkDiv;
310 } else {
311 /* PLL PerClk feedback */
312 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
313 sysInfo->pllExtBusDiv;
314 }
315
316 /* Now calculate the individual clocks */
317 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
318 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
319 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
320 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
321 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
322 sysInfo->freqDDR = sysInfo->freqPLB;
323 sysInfo->freqUART = sysInfo->freqPLB;
324
325 return;
326}
327
328#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200329 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200330void get_sys_info (sys_info_t *sysInfo)
331{
332 unsigned long temp;
333 unsigned long reg;
334 unsigned long lfdiv;
335 unsigned long m;
336 unsigned long prbdv0;
337 /*
338 WARNING: ASSUMES the following:
339 ENG=1
340 PRADV0=1
341 PRBDV0=1
342 */
343
344 /* Decode CPR0_PLLD0 for divisors */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200345 mfcpr(clk_plld, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200346 temp = (reg & PLLD_FWDVA_MASK) >> 16;
347 sysInfo->pllFwdDivA = temp ? temp : 16;
348 temp = (reg & PLLD_FWDVB_MASK) >> 8;
349 sysInfo->pllFwdDivB = temp ? temp: 8 ;
350 temp = (reg & PLLD_FBDV_MASK) >> 24;
351 sysInfo->pllFbkDiv = temp ? temp : 32;
352 lfdiv = reg & PLLD_LFBDV_MASK;
353
Stefan Roese087dfdb2007-10-21 08:12:41 +0200354 mfcpr(clk_opbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200355 temp = (reg & OPBDDV_MASK) >> 24;
356 sysInfo->pllOpbDiv = temp ? temp : 4;
357
Stefan Roese087dfdb2007-10-21 08:12:41 +0200358 mfcpr(clk_perd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200359 temp = (reg & PERDV_MASK) >> 24;
360 sysInfo->pllExtBusDiv = temp ? temp : 8;
361
Stefan Roese087dfdb2007-10-21 08:12:41 +0200362 mfcpr(clk_primbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200363 temp = (reg & PRBDV_MASK) >> 24;
364 prbdv0 = temp ? temp : 8;
365
Stefan Roese087dfdb2007-10-21 08:12:41 +0200366 mfcpr(clk_spcid, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200367 temp = (reg & SPCID_MASK) >> 24;
368 sysInfo->pllPciDiv = temp ? temp : 4;
369
370 /* Calculate 'M' based on feedback source */
371 mfsdr(sdr_sdstp0, reg);
372 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
373 if (temp == 0) { /* PLL output */
374 /* Figure which pll to use */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200375 mfcpr(clk_pllc, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200376 temp = (reg & PLLC_SRC_MASK) >> 29;
377 if (!temp) /* PLLOUTA */
378 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
379 else /* PLLOUTB */
380 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
381 }
382 else if (temp == 1) /* CPU output */
383 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
384 else /* PerClk */
385 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
386
387 /* Now calculate the individual clocks */
388 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
389 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
390 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
391 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200392 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200393 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200394 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200395
396 /* Figure which timer source to use */
Matthias Fuchs58ea1422009-07-22 17:27:56 +0200397 if (mfspr(SPRN_CCR1) & 0x0080) {
398 /* External Clock, assume same as SYS_CLK */
Stefan Roesec157d8e2005-08-01 16:41:48 +0200399 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
400 if (CONFIG_SYS_CLK_FREQ > temp)
401 sysInfo->freqTmrClk = temp;
402 else
403 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
404 }
405 else /* Internal clock */
406 sysInfo->freqTmrClk = sysInfo->freqProcessor;
407}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200408
Stefan Roesec157d8e2005-08-01 16:41:48 +0200409/********************************************
410 * get_PCI_freq
411 * return PCI bus freq in Hz
412 *********************************************/
413ulong get_PCI_freq (void)
414{
415 sys_info_t sys_info;
416 get_sys_info (&sys_info);
417 return sys_info.freqPCI;
418}
419
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200420#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
421 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000422void get_sys_info (sys_info_t * sysInfo)
423{
424 unsigned long strp0;
425 unsigned long temp;
426 unsigned long m;
427
428 /* Extract configured divisors */
429 strp0 = mfdcr( cpc0_strp0 );
430 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
431 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
432 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
433 sysInfo->pllFbkDiv = temp ? temp : 16;
434 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
435 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
436
437 /* Calculate 'M' based on feedback source */
438 if( strp0 & PLLSYS0_EXTSL_MASK )
439 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
440 else
441 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
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;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200447 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
448 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000449 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200450 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200451 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000452}
wdenkba56f622004-02-06 23:19:44 +0000453#else
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200454
455#if !defined(CONFIG_XILINX_440)
wdenkba56f622004-02-06 23:19:44 +0000456void get_sys_info (sys_info_t * sysInfo)
457{
458 unsigned long strp0;
459 unsigned long strp1;
460 unsigned long temp;
461 unsigned long temp1;
462 unsigned long lfdiv;
463 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000464 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000465
Stefan Roese4745aca2007-02-20 10:57:08 +0100466#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200467 unsigned long sys_freq;
468 unsigned long sys_per=0;
469 unsigned long msr;
470 unsigned long pci_clock_per;
471 unsigned long sdr_ddrpll;
472
473 /*-------------------------------------------------------------------------+
474 | Get the system clock period.
475 +-------------------------------------------------------------------------*/
476 sys_per = determine_sysper();
477
478 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
479
480 /*-------------------------------------------------------------------------+
481 | Calculate the system clock speed from the period.
482 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100483 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200484#endif
485
wdenkba56f622004-02-06 23:19:44 +0000486 /* Extract configured divisors */
487 mfsdr( sdr_sdstp0,strp0 );
488 mfsdr( sdr_sdstp1,strp1 );
489
490 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
491 sysInfo->pllFwdDivA = temp ? temp : 16 ;
492 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
493 sysInfo->pllFwdDivB = temp ? temp: 8 ;
494 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
495 sysInfo->pllFbkDiv = temp ? temp : 32;
496 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
497 sysInfo->pllOpbDiv = temp ? temp : 4;
498 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
499 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000500 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000501
502 /* Calculate 'M' based on feedback source */
503 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
504 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
505 lfdiv = temp1 ? temp1 : 64;
506 if (temp == 0) { /* PLL output */
507 /* Figure which pll to use */
508 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
509 if (!temp)
510 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
511 else
512 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
513 }
514 else if (temp == 1) /* CPU output */
515 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
516 else /* PerClk */
517 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
518
519 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100520#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200521 sysInfo->freqVCOMhz = (m * sys_freq) ;
522#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100523 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200524#endif
wdenkba56f622004-02-06 23:19:44 +0000525 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000526 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000527 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200528 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000529
Stefan Roese4745aca2007-02-20 10:57:08 +0100530#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200531 /* Determine PCI Clock Period */
532 pci_clock_per = determine_pci_clock_per();
533 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
534 mfsdr(sdr_ddr0, sdr_ddrpll);
535 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
536#endif
537
Stefan Roesefa8aea22007-10-22 07:33:52 +0200538 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200539}
540
541#endif
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200542#endif /* CONFIG_XILINX_440 */
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200543
Stefan Roese4745aca2007-02-20 10:57:08 +0100544#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200545unsigned long determine_sysper(void)
546{
547 unsigned int fpga_clocking_reg;
548 unsigned int master_clock_selection;
549 unsigned long master_clock_per = 0;
550 unsigned long fb_div_selection;
551 unsigned int vco_div_reg_value;
552 unsigned long vco_div_selection;
553 unsigned long sys_per = 0;
554 int extClkVal;
555
556 /*-------------------------------------------------------------------------+
557 | Read FPGA reg 0 and reg 1 to get FPGA reg information
558 +-------------------------------------------------------------------------*/
559 fpga_clocking_reg = in16(FPGA_REG16);
560
561
562 /* Determine Master Clock Source Selection */
563 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
564
565 switch(master_clock_selection) {
566 case FPGA_REG16_MASTER_CLK_66_66:
567 master_clock_per = PERIOD_66_66MHZ;
568 break;
569 case FPGA_REG16_MASTER_CLK_50:
570 master_clock_per = PERIOD_50_00MHZ;
571 break;
572 case FPGA_REG16_MASTER_CLK_33_33:
573 master_clock_per = PERIOD_33_33MHZ;
574 break;
575 case FPGA_REG16_MASTER_CLK_25:
576 master_clock_per = PERIOD_25_00MHZ;
577 break;
578 case FPGA_REG16_MASTER_CLK_EXT:
579 if ((extClkVal==EXTCLK_33_33)
580 && (extClkVal==EXTCLK_50)
581 && (extClkVal==EXTCLK_66_66)
582 && (extClkVal==EXTCLK_83)) {
583 /* calculate master clock period from external clock value */
584 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
585 } else {
586 /* Unsupported */
587 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
588 hang();
589 }
590 break;
591 default:
592 /* Unsupported */
593 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
594 hang();
595 break;
596 }
597
598 /* Determine FB divisors values */
599 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
600 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
601 fb_div_selection = FPGA_FB_DIV_6;
602 else
603 fb_div_selection = FPGA_FB_DIV_12;
604 } else {
605 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
606 fb_div_selection = FPGA_FB_DIV_10;
607 else
608 fb_div_selection = FPGA_FB_DIV_20;
609 }
610
611 /* Determine VCO divisors values */
612 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
613
614 switch(vco_div_reg_value) {
615 case FPGA_REG16_VCO_DIV_4:
616 vco_div_selection = FPGA_VCO_DIV_4;
617 break;
618 case FPGA_REG16_VCO_DIV_6:
619 vco_div_selection = FPGA_VCO_DIV_6;
620 break;
621 case FPGA_REG16_VCO_DIV_8:
622 vco_div_selection = FPGA_VCO_DIV_8;
623 break;
624 case FPGA_REG16_VCO_DIV_10:
625 default:
626 vco_div_selection = FPGA_VCO_DIV_10;
627 break;
628 }
629
630 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
631 switch(master_clock_per) {
632 case PERIOD_25_00MHZ:
633 if (fb_div_selection == FPGA_FB_DIV_12) {
634 if (vco_div_selection == FPGA_VCO_DIV_4)
635 sys_per = PERIOD_75_00MHZ;
636 if (vco_div_selection == FPGA_VCO_DIV_6)
637 sys_per = PERIOD_50_00MHZ;
638 }
639 break;
640 case PERIOD_33_33MHZ:
641 if (fb_div_selection == FPGA_FB_DIV_6) {
642 if (vco_div_selection == FPGA_VCO_DIV_4)
643 sys_per = PERIOD_50_00MHZ;
644 if (vco_div_selection == FPGA_VCO_DIV_6)
645 sys_per = PERIOD_33_33MHZ;
646 }
647 if (fb_div_selection == FPGA_FB_DIV_10) {
648 if (vco_div_selection == FPGA_VCO_DIV_4)
649 sys_per = PERIOD_83_33MHZ;
650 if (vco_div_selection == FPGA_VCO_DIV_10)
651 sys_per = PERIOD_33_33MHZ;
652 }
653 if (fb_div_selection == FPGA_FB_DIV_12) {
654 if (vco_div_selection == FPGA_VCO_DIV_4)
655 sys_per = PERIOD_100_00MHZ;
656 if (vco_div_selection == FPGA_VCO_DIV_6)
657 sys_per = PERIOD_66_66MHZ;
658 if (vco_div_selection == FPGA_VCO_DIV_8)
659 sys_per = PERIOD_50_00MHZ;
660 }
661 break;
662 case PERIOD_50_00MHZ:
663 if (fb_div_selection == FPGA_FB_DIV_6) {
664 if (vco_div_selection == FPGA_VCO_DIV_4)
665 sys_per = PERIOD_75_00MHZ;
666 if (vco_div_selection == FPGA_VCO_DIV_6)
667 sys_per = PERIOD_50_00MHZ;
668 }
669 if (fb_div_selection == FPGA_FB_DIV_10) {
670 if (vco_div_selection == FPGA_VCO_DIV_6)
671 sys_per = PERIOD_83_33MHZ;
672 if (vco_div_selection == FPGA_VCO_DIV_10)
673 sys_per = PERIOD_50_00MHZ;
674 }
675 if (fb_div_selection == FPGA_FB_DIV_12) {
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_100_00MHZ;
678 if (vco_div_selection == FPGA_VCO_DIV_8)
679 sys_per = PERIOD_75_00MHZ;
680 }
681 break;
682 case PERIOD_66_66MHZ:
683 if (fb_div_selection == FPGA_FB_DIV_6) {
684 if (vco_div_selection == FPGA_VCO_DIV_4)
685 sys_per = PERIOD_100_00MHZ;
686 if (vco_div_selection == FPGA_VCO_DIV_6)
687 sys_per = PERIOD_66_66MHZ;
688 if (vco_div_selection == FPGA_VCO_DIV_8)
689 sys_per = PERIOD_50_00MHZ;
690 }
691 if (fb_div_selection == FPGA_FB_DIV_10) {
692 if (vco_div_selection == FPGA_VCO_DIV_8)
693 sys_per = PERIOD_83_33MHZ;
694 if (vco_div_selection == FPGA_VCO_DIV_10)
695 sys_per = PERIOD_66_66MHZ;
696 }
697 if (fb_div_selection == FPGA_FB_DIV_12) {
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_100_00MHZ;
700 }
701 break;
702 default:
703 break;
704 }
705
706 if (sys_per == 0) {
707 /* Other combinations are not supported */
708 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
709 hang();
710 }
711 } else {
712 /* calcul system clock without cheking */
713 /* if engineering option clock no check is selected */
714 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
715 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
716 }
717
718 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200719}
720
721/*-------------------------------------------------------------------------+
722| determine_pci_clock_per.
723+-------------------------------------------------------------------------*/
724unsigned long determine_pci_clock_per(void)
725{
726 unsigned long pci_clock_selection, pci_period;
727
728 /*-------------------------------------------------------------------------+
729 | Read FPGA reg 6 to get PCI 0 FPGA reg information
730 +-------------------------------------------------------------------------*/
731 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
732
733
734 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
735
736 switch (pci_clock_selection) {
737 case FPGA_REG16_PCI0_CLK_133_33:
738 pci_period = PERIOD_133_33MHZ;
739 break;
740 case FPGA_REG16_PCI0_CLK_100:
741 pci_period = PERIOD_100_00MHZ;
742 break;
743 case FPGA_REG16_PCI0_CLK_66_66:
744 pci_period = PERIOD_66_66MHZ;
745 break;
746 default:
747 pci_period = PERIOD_33_33MHZ;;
748 break;
749 }
750
751 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000752}
753#endif
wdenkc6097192002-11-03 00:24:07 +0000754
755ulong get_OPB_freq (void)
756{
757
758 sys_info_t sys_info;
759 get_sys_info (&sys_info);
760 return sys_info.freqOPB;
761}
762
Michal Simek9fea65a2008-06-24 09:54:09 +0200763#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000764extern void get_sys_info (sys_info_t * sysInfo);
765extern ulong get_PCI_freq (void);
766
Wolfgang Denk7521af12005-10-09 01:04:33 +0200767#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200768void get_sys_info (sys_info_t * sysInfo)
769{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200770 sysInfo->freqProcessor = 240 * 1000 * 1000;
771 sysInfo->freqPLB = 80 * 1000 * 1000;
772 sysInfo->freqPCI = 33 * 1000 * 1000;
773}
774
wdenkc6097192002-11-03 00:24:07 +0000775#elif defined(CONFIG_405)
776
Stefan Roesefa8aea22007-10-22 07:33:52 +0200777void get_sys_info (sys_info_t * sysInfo)
778{
wdenkc6097192002-11-03 00:24:07 +0000779 sysInfo->freqVCOMhz=3125000;
780 sysInfo->freqProcessor=12*1000*1000;
781 sysInfo->freqPLB=50*1000*1000;
782 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000783}
784
stroeseb867d702003-05-23 11:18:02 +0000785#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200786void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000787{
788 unsigned long pllmr0;
789 unsigned long pllmr1;
790 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
791 unsigned long m;
792 unsigned long pllmr0_ccdv;
793
794 /*
795 * Read PLL Mode registers
796 */
797 pllmr0 = mfdcr (cpc0_pllmr0);
798 pllmr1 = mfdcr (cpc0_pllmr1);
799
800 /*
801 * Determine forward divider A
802 */
803 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
804
805 /*
806 * Determine forward divider B (should be equal to A)
807 */
808 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
809
810 /*
811 * Determine FBK_DIV.
812 */
813 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200814 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000815 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000816
817 /*
818 * Determine PLB_DIV.
819 */
820 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
821
822 /*
823 * Determine PCI_DIV.
824 */
825 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
826
827 /*
828 * Determine EXTBUS_DIV.
829 */
830 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
831
832 /*
833 * Determine OPB_DIV.
834 */
835 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
836
837 /*
838 * Determine the M factor
839 */
840 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
841
842 /*
843 * Determine VCO clock frequency
844 */
stroeseb39392a2004-12-16 18:13:53 +0000845 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
846 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000847
848 /*
849 * Determine CPU clock frequency
850 */
851 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
852 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000853 /*
854 * This is true if FWDVA == FWDVB:
855 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
856 * / pllmr0_ccdv;
857 */
858 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
859 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000860 } else {
861 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
862 }
863
864 /*
865 * Determine PLB clock frequency
866 */
867 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200868
869 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200870
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200871 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
872
Stefan Roesefa8aea22007-10-22 07:33:52 +0200873 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000874}
875
876
877/********************************************
878 * get_OPB_freq
879 * return OPB bus freq in Hz
880 *********************************************/
881ulong get_OPB_freq (void)
882{
883 ulong val = 0;
884
Stefan Roese087dfdb2007-10-21 08:12:41 +0200885 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000886
887 get_sys_info (&sys_info);
888 val = sys_info.freqPLB / sys_info.pllOpbDiv;
889
890 return val;
891}
892
893
894/********************************************
895 * get_PCI_freq
896 * return PCI bus freq in Hz
897 *********************************************/
898ulong get_PCI_freq (void)
899{
900 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200901 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000902
903 get_sys_info (&sys_info);
904 val = sys_info.freqPLB / sys_info.pllPciDiv;
905 return val;
906}
907
Stefan Roesee01bd212007-03-21 13:38:59 +0100908#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200909void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100910{
911 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200912 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100913 unsigned long cpr_primad;
914 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
915 unsigned long primad_cpudv;
916 unsigned long m;
917
918 /*
919 * Read PLL Mode registers
920 */
921 mfcpr(cprplld, cpr_plld);
Stefan Roese273db7e2007-08-13 09:05:33 +0200922 mfcpr(cprpllc, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100923
924 /*
925 * Determine forward divider A
926 */
927 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
928
929 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200930 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100931 */
932 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200933 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100934 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100935
936 /*
937 * Determine FBK_DIV.
938 */
939 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200940 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100941 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100942
943 /*
944 * Read CPR_PRIMAD register
945 */
946 mfcpr(cprprimad, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200947
Stefan Roesee01bd212007-03-21 13:38:59 +0100948 /*
949 * Determine PLB_DIV.
950 */
951 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200952 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100953 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100954
955 /*
956 * Determine EXTBUS_DIV.
957 */
958 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200959 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100960 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100961
962 /*
963 * Determine OPB_DIV.
964 */
965 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200966 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100967 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100968
969 /*
970 * Determine the M factor
971 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200972 if (cpr_pllc & PLLC_SRC_MASK)
973 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
974 else
975 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100976
977 /*
978 * Determine VCO clock frequency
979 */
980 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
981 (unsigned long long)sysClkPeriodPs;
982
983 /*
984 * Determine CPU clock frequency
985 */
986 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200987 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100988 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100989
Stefan Roese273db7e2007-08-13 09:05:33 +0200990 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
991 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100992
993 /*
994 * Determine PLB clock frequency
995 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200996 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
997 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200998
999 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1000 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001001
1002 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roesee01bd212007-03-21 13:38:59 +01001003}
1004
1005/********************************************
1006 * get_OPB_freq
1007 * return OPB bus freq in Hz
1008 *********************************************/
1009ulong get_OPB_freq (void)
1010{
1011 ulong val = 0;
1012
Stefan Roese087dfdb2007-10-21 08:12:41 +02001013 PPC4xx_SYS_INFO sys_info;
Stefan Roesee01bd212007-03-21 13:38:59 +01001014
1015 get_sys_info (&sys_info);
1016 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1017
1018 return val;
1019}
1020
Stefan Roesedbbd1252007-10-05 17:10:59 +02001021#elif defined(CONFIG_405EX)
1022
1023/*
1024 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1025 * We need the specs!!!!
1026 */
1027static unsigned char get_fbdv(unsigned char index)
1028{
1029 unsigned char ret = 0;
1030 /* This is table should be 256 bytes.
1031 * Only take first 52 values.
1032 */
1033 unsigned char fbdv_tb[] = {
1034 0x00, 0xff, 0x7f, 0xfd,
1035 0x7a, 0xf5, 0x6a, 0xd5,
1036 0x2a, 0xd4, 0x29, 0xd3,
1037 0x26, 0xcc, 0x19, 0xb3,
1038 0x67, 0xce, 0x1d, 0xbb,
1039 0x77, 0xee, 0x5d, 0xba,
1040 0x74, 0xe9, 0x52, 0xa5,
1041 0x4b, 0x96, 0x2c, 0xd8,
1042 0x31, 0xe3, 0x46, 0x8d,
1043 0x1b, 0xb7, 0x6f, 0xde,
1044 0x3d, 0xfb, 0x76, 0xed,
1045 0x5a, 0xb5, 0x6b, 0xd6,
1046 0x2d, 0xdb, 0x36, 0xec,
1047
1048 };
1049
1050 if ((index & 0x7f) == 0)
1051 return 1;
1052 while (ret < sizeof (fbdv_tb)) {
1053 if (fbdv_tb[ret] == index)
1054 break;
1055 ret++;
1056 }
1057 ret++;
1058
1059 return ret;
1060}
1061
1062#define PLL_FBK_PLL_LOCAL 0
1063#define PLL_FBK_CPU 1
1064#define PLL_FBK_PERCLK 5
1065
1066void get_sys_info (sys_info_t * sysInfo)
1067{
1068 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1069 unsigned long m = 1;
1070 unsigned int tmp;
1071 unsigned char fwdva[16] = {
1072 1, 2, 14, 9, 4, 11, 16, 13,
1073 12, 5, 6, 15, 10, 7, 8, 3,
1074 };
1075 unsigned char sel, cpudv0, plb2xDiv;
1076
1077 mfcpr(cpr0_plld, tmp);
1078
1079 /*
1080 * Determine forward divider A
1081 */
1082 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1083
1084 /*
1085 * Determine FBK_DIV.
1086 */
1087 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1088
1089 /*
1090 * Determine PLBDV0
1091 */
1092 sysInfo->pllPlbDiv = 2;
1093
1094 /*
1095 * Determine PERDV0
1096 */
1097 mfcpr(cpr0_perd, tmp);
1098 tmp = (tmp >> 24) & 0x03;
1099 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1100
1101 /*
1102 * Determine OPBDV0
1103 */
1104 mfcpr(cpr0_opbd, tmp);
1105 tmp = (tmp >> 24) & 0x03;
1106 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1107
1108 /* Determine PLB2XDV0 */
1109 mfcpr(cpr0_plbd, tmp);
1110 tmp = (tmp >> 16) & 0x07;
1111 plb2xDiv = (tmp == 0) ? 8 : tmp;
1112
1113 /* Determine CPUDV0 */
1114 mfcpr(cpr0_cpud, tmp);
1115 tmp = (tmp >> 24) & 0x07;
1116 cpudv0 = (tmp == 0) ? 8 : tmp;
1117
1118 /* Determine SEL(5:7) in CPR0_PLLC */
1119 mfcpr(cpr0_pllc, tmp);
1120 sel = (tmp >> 24) & 0x07;
1121
1122 /*
1123 * Determine the M factor
1124 * PLL local: M = FBDV
1125 * CPU clock: M = FBDV * FWDVA * CPUDV0
1126 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1127 *
1128 */
1129 switch (sel) {
1130 case PLL_FBK_CPU:
1131 m = sysInfo->pllFwdDiv * cpudv0;
1132 break;
1133 case PLL_FBK_PERCLK:
1134 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1135 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1136 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001137 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001138 break;
1139 default:
1140 printf("%s unknown m\n", __FUNCTION__);
1141 return;
1142
1143 }
1144 m *= sysInfo->pllFbkDiv;
1145
1146 /*
1147 * Determine VCO clock frequency
1148 */
1149 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1150 (unsigned long long)sysClkPeriodPs;
1151
1152 /*
1153 * Determine CPU clock frequency
1154 */
1155 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1156
1157 /*
1158 * Determine PLB clock frequency, ddr1x should be the same
1159 */
1160 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1161 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1162 sysInfo->freqDDR = sysInfo->freqPLB;
1163 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001164 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001165}
1166
1167/********************************************
1168 * get_OPB_freq
1169 * return OPB bus freq in Hz
1170 *********************************************/
1171ulong get_OPB_freq (void)
1172{
1173 ulong val = 0;
1174
Stefan Roese087dfdb2007-10-21 08:12:41 +02001175 PPC4xx_SYS_INFO sys_info;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001176
1177 get_sys_info (&sys_info);
1178 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1179
1180 return val;
1181}
1182
wdenkc6097192002-11-03 00:24:07 +00001183#endif
1184
1185int get_clocks (void)
1186{
Stefan Roesee01bd212007-03-21 13:38:59 +01001187#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1190 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001191 sys_info_t sys_info;
1192
1193 get_sys_info (&sys_info);
1194 gd->cpu_clk = sys_info.freqProcessor;
1195 gd->bus_clk = sys_info.freqPLB;
1196
1197#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1198
1199#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001200 gd->cpu_clk = 66000000;
1201 gd->bus_clk = 66000000;
1202#endif
1203 return (0);
1204}
1205
1206
1207/********************************************
1208 * get_bus_freq
1209 * return PLB bus freq in Hz
1210 *********************************************/
1211ulong get_bus_freq (ulong dummy)
1212{
1213 ulong val;
1214
Stefan Roesee01bd212007-03-21 13:38:59 +01001215#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1216 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001217 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1218 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001219 sys_info_t sys_info;
1220
1221 get_sys_info (&sys_info);
1222 val = sys_info.freqPLB;
1223
1224#elif defined(CONFIG_IOP480)
1225
1226 val = 66;
1227
1228#else
1229# error get_bus_freq() not implemented
1230#endif
1231
1232 return val;
1233}