blob: 6cb93f3f1789956fcaee864ce705bafcd941ea5e [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 */
397 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
398 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
399 if (CONFIG_SYS_CLK_FREQ > temp)
400 sysInfo->freqTmrClk = temp;
401 else
402 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
403 }
404 else /* Internal clock */
405 sysInfo->freqTmrClk = sysInfo->freqProcessor;
406}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200407
Stefan Roesec157d8e2005-08-01 16:41:48 +0200408/********************************************
409 * get_PCI_freq
410 * return PCI bus freq in Hz
411 *********************************************/
412ulong get_PCI_freq (void)
413{
414 sys_info_t sys_info;
415 get_sys_info (&sys_info);
416 return sys_info.freqPCI;
417}
418
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200419#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
420 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000421void get_sys_info (sys_info_t * sysInfo)
422{
423 unsigned long strp0;
424 unsigned long temp;
425 unsigned long m;
426
427 /* Extract configured divisors */
428 strp0 = mfdcr( cpc0_strp0 );
429 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
430 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
431 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
432 sysInfo->pllFbkDiv = temp ? temp : 16;
433 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
434 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
435
436 /* Calculate 'M' based on feedback source */
437 if( strp0 & PLLSYS0_EXTSL_MASK )
438 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
439 else
440 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
441
442 /* Now calculate the individual clocks */
443 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
444 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
445 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200446 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
447 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000448 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200449 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200450 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000451}
wdenkba56f622004-02-06 23:19:44 +0000452#else
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200453
454#if !defined(CONFIG_XILINX_440)
wdenkba56f622004-02-06 23:19:44 +0000455void get_sys_info (sys_info_t * sysInfo)
456{
457 unsigned long strp0;
458 unsigned long strp1;
459 unsigned long temp;
460 unsigned long temp1;
461 unsigned long lfdiv;
462 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000463 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000464
Stefan Roese4745aca2007-02-20 10:57:08 +0100465#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200466 unsigned long sys_freq;
467 unsigned long sys_per=0;
468 unsigned long msr;
469 unsigned long pci_clock_per;
470 unsigned long sdr_ddrpll;
471
472 /*-------------------------------------------------------------------------+
473 | Get the system clock period.
474 +-------------------------------------------------------------------------*/
475 sys_per = determine_sysper();
476
477 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
478
479 /*-------------------------------------------------------------------------+
480 | Calculate the system clock speed from the period.
481 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100482 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200483#endif
484
wdenkba56f622004-02-06 23:19:44 +0000485 /* Extract configured divisors */
486 mfsdr( sdr_sdstp0,strp0 );
487 mfsdr( sdr_sdstp1,strp1 );
488
489 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
490 sysInfo->pllFwdDivA = temp ? temp : 16 ;
491 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
492 sysInfo->pllFwdDivB = temp ? temp: 8 ;
493 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
494 sysInfo->pllFbkDiv = temp ? temp : 32;
495 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
496 sysInfo->pllOpbDiv = temp ? temp : 4;
497 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
498 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000499 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000500
501 /* Calculate 'M' based on feedback source */
502 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
503 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
504 lfdiv = temp1 ? temp1 : 64;
505 if (temp == 0) { /* PLL output */
506 /* Figure which pll to use */
507 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
508 if (!temp)
509 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
510 else
511 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
512 }
513 else if (temp == 1) /* CPU output */
514 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
515 else /* PerClk */
516 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
517
518 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100519#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200520 sysInfo->freqVCOMhz = (m * sys_freq) ;
521#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100522 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200523#endif
wdenkba56f622004-02-06 23:19:44 +0000524 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000525 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000526 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200527 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000528
Stefan Roese4745aca2007-02-20 10:57:08 +0100529#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200530 /* Determine PCI Clock Period */
531 pci_clock_per = determine_pci_clock_per();
532 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
533 mfsdr(sdr_ddr0, sdr_ddrpll);
534 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
535#endif
536
Stefan Roesefa8aea22007-10-22 07:33:52 +0200537 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200538}
539
540#endif
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200541#endif /* CONFIG_XILINX_440 */
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200542
Stefan Roese4745aca2007-02-20 10:57:08 +0100543#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200544unsigned long determine_sysper(void)
545{
546 unsigned int fpga_clocking_reg;
547 unsigned int master_clock_selection;
548 unsigned long master_clock_per = 0;
549 unsigned long fb_div_selection;
550 unsigned int vco_div_reg_value;
551 unsigned long vco_div_selection;
552 unsigned long sys_per = 0;
553 int extClkVal;
554
555 /*-------------------------------------------------------------------------+
556 | Read FPGA reg 0 and reg 1 to get FPGA reg information
557 +-------------------------------------------------------------------------*/
558 fpga_clocking_reg = in16(FPGA_REG16);
559
560
561 /* Determine Master Clock Source Selection */
562 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
563
564 switch(master_clock_selection) {
565 case FPGA_REG16_MASTER_CLK_66_66:
566 master_clock_per = PERIOD_66_66MHZ;
567 break;
568 case FPGA_REG16_MASTER_CLK_50:
569 master_clock_per = PERIOD_50_00MHZ;
570 break;
571 case FPGA_REG16_MASTER_CLK_33_33:
572 master_clock_per = PERIOD_33_33MHZ;
573 break;
574 case FPGA_REG16_MASTER_CLK_25:
575 master_clock_per = PERIOD_25_00MHZ;
576 break;
577 case FPGA_REG16_MASTER_CLK_EXT:
578 if ((extClkVal==EXTCLK_33_33)
579 && (extClkVal==EXTCLK_50)
580 && (extClkVal==EXTCLK_66_66)
581 && (extClkVal==EXTCLK_83)) {
582 /* calculate master clock period from external clock value */
583 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
584 } else {
585 /* Unsupported */
586 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
587 hang();
588 }
589 break;
590 default:
591 /* Unsupported */
592 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
593 hang();
594 break;
595 }
596
597 /* Determine FB divisors values */
598 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
599 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
600 fb_div_selection = FPGA_FB_DIV_6;
601 else
602 fb_div_selection = FPGA_FB_DIV_12;
603 } else {
604 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
605 fb_div_selection = FPGA_FB_DIV_10;
606 else
607 fb_div_selection = FPGA_FB_DIV_20;
608 }
609
610 /* Determine VCO divisors values */
611 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
612
613 switch(vco_div_reg_value) {
614 case FPGA_REG16_VCO_DIV_4:
615 vco_div_selection = FPGA_VCO_DIV_4;
616 break;
617 case FPGA_REG16_VCO_DIV_6:
618 vco_div_selection = FPGA_VCO_DIV_6;
619 break;
620 case FPGA_REG16_VCO_DIV_8:
621 vco_div_selection = FPGA_VCO_DIV_8;
622 break;
623 case FPGA_REG16_VCO_DIV_10:
624 default:
625 vco_div_selection = FPGA_VCO_DIV_10;
626 break;
627 }
628
629 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
630 switch(master_clock_per) {
631 case PERIOD_25_00MHZ:
632 if (fb_div_selection == FPGA_FB_DIV_12) {
633 if (vco_div_selection == FPGA_VCO_DIV_4)
634 sys_per = PERIOD_75_00MHZ;
635 if (vco_div_selection == FPGA_VCO_DIV_6)
636 sys_per = PERIOD_50_00MHZ;
637 }
638 break;
639 case PERIOD_33_33MHZ:
640 if (fb_div_selection == FPGA_FB_DIV_6) {
641 if (vco_div_selection == FPGA_VCO_DIV_4)
642 sys_per = PERIOD_50_00MHZ;
643 if (vco_div_selection == FPGA_VCO_DIV_6)
644 sys_per = PERIOD_33_33MHZ;
645 }
646 if (fb_div_selection == FPGA_FB_DIV_10) {
647 if (vco_div_selection == FPGA_VCO_DIV_4)
648 sys_per = PERIOD_83_33MHZ;
649 if (vco_div_selection == FPGA_VCO_DIV_10)
650 sys_per = PERIOD_33_33MHZ;
651 }
652 if (fb_div_selection == FPGA_FB_DIV_12) {
653 if (vco_div_selection == FPGA_VCO_DIV_4)
654 sys_per = PERIOD_100_00MHZ;
655 if (vco_div_selection == FPGA_VCO_DIV_6)
656 sys_per = PERIOD_66_66MHZ;
657 if (vco_div_selection == FPGA_VCO_DIV_8)
658 sys_per = PERIOD_50_00MHZ;
659 }
660 break;
661 case PERIOD_50_00MHZ:
662 if (fb_div_selection == FPGA_FB_DIV_6) {
663 if (vco_div_selection == FPGA_VCO_DIV_4)
664 sys_per = PERIOD_75_00MHZ;
665 if (vco_div_selection == FPGA_VCO_DIV_6)
666 sys_per = PERIOD_50_00MHZ;
667 }
668 if (fb_div_selection == FPGA_FB_DIV_10) {
669 if (vco_div_selection == FPGA_VCO_DIV_6)
670 sys_per = PERIOD_83_33MHZ;
671 if (vco_div_selection == FPGA_VCO_DIV_10)
672 sys_per = PERIOD_50_00MHZ;
673 }
674 if (fb_div_selection == FPGA_FB_DIV_12) {
675 if (vco_div_selection == FPGA_VCO_DIV_6)
676 sys_per = PERIOD_100_00MHZ;
677 if (vco_div_selection == FPGA_VCO_DIV_8)
678 sys_per = PERIOD_75_00MHZ;
679 }
680 break;
681 case PERIOD_66_66MHZ:
682 if (fb_div_selection == FPGA_FB_DIV_6) {
683 if (vco_div_selection == FPGA_VCO_DIV_4)
684 sys_per = PERIOD_100_00MHZ;
685 if (vco_div_selection == FPGA_VCO_DIV_6)
686 sys_per = PERIOD_66_66MHZ;
687 if (vco_div_selection == FPGA_VCO_DIV_8)
688 sys_per = PERIOD_50_00MHZ;
689 }
690 if (fb_div_selection == FPGA_FB_DIV_10) {
691 if (vco_div_selection == FPGA_VCO_DIV_8)
692 sys_per = PERIOD_83_33MHZ;
693 if (vco_div_selection == FPGA_VCO_DIV_10)
694 sys_per = PERIOD_66_66MHZ;
695 }
696 if (fb_div_selection == FPGA_FB_DIV_12) {
697 if (vco_div_selection == FPGA_VCO_DIV_8)
698 sys_per = PERIOD_100_00MHZ;
699 }
700 break;
701 default:
702 break;
703 }
704
705 if (sys_per == 0) {
706 /* Other combinations are not supported */
707 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
708 hang();
709 }
710 } else {
711 /* calcul system clock without cheking */
712 /* if engineering option clock no check is selected */
713 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
714 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
715 }
716
717 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200718}
719
720/*-------------------------------------------------------------------------+
721| determine_pci_clock_per.
722+-------------------------------------------------------------------------*/
723unsigned long determine_pci_clock_per(void)
724{
725 unsigned long pci_clock_selection, pci_period;
726
727 /*-------------------------------------------------------------------------+
728 | Read FPGA reg 6 to get PCI 0 FPGA reg information
729 +-------------------------------------------------------------------------*/
730 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
731
732
733 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
734
735 switch (pci_clock_selection) {
736 case FPGA_REG16_PCI0_CLK_133_33:
737 pci_period = PERIOD_133_33MHZ;
738 break;
739 case FPGA_REG16_PCI0_CLK_100:
740 pci_period = PERIOD_100_00MHZ;
741 break;
742 case FPGA_REG16_PCI0_CLK_66_66:
743 pci_period = PERIOD_66_66MHZ;
744 break;
745 default:
746 pci_period = PERIOD_33_33MHZ;;
747 break;
748 }
749
750 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000751}
752#endif
wdenkc6097192002-11-03 00:24:07 +0000753
754ulong get_OPB_freq (void)
755{
756
757 sys_info_t sys_info;
758 get_sys_info (&sys_info);
759 return sys_info.freqOPB;
760}
761
Michal Simek9fea65a2008-06-24 09:54:09 +0200762#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000763extern void get_sys_info (sys_info_t * sysInfo);
764extern ulong get_PCI_freq (void);
765
Wolfgang Denk7521af12005-10-09 01:04:33 +0200766#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200767void get_sys_info (sys_info_t * sysInfo)
768{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200769 sysInfo->freqProcessor = 240 * 1000 * 1000;
770 sysInfo->freqPLB = 80 * 1000 * 1000;
771 sysInfo->freqPCI = 33 * 1000 * 1000;
772}
773
wdenkc6097192002-11-03 00:24:07 +0000774#elif defined(CONFIG_405)
775
Stefan Roesefa8aea22007-10-22 07:33:52 +0200776void get_sys_info (sys_info_t * sysInfo)
777{
wdenkc6097192002-11-03 00:24:07 +0000778 sysInfo->freqVCOMhz=3125000;
779 sysInfo->freqProcessor=12*1000*1000;
780 sysInfo->freqPLB=50*1000*1000;
781 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000782}
783
stroeseb867d702003-05-23 11:18:02 +0000784#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200785void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000786{
787 unsigned long pllmr0;
788 unsigned long pllmr1;
789 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
790 unsigned long m;
791 unsigned long pllmr0_ccdv;
792
793 /*
794 * Read PLL Mode registers
795 */
796 pllmr0 = mfdcr (cpc0_pllmr0);
797 pllmr1 = mfdcr (cpc0_pllmr1);
798
799 /*
800 * Determine forward divider A
801 */
802 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
803
804 /*
805 * Determine forward divider B (should be equal to A)
806 */
807 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
808
809 /*
810 * Determine FBK_DIV.
811 */
812 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200813 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000814 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000815
816 /*
817 * Determine PLB_DIV.
818 */
819 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
820
821 /*
822 * Determine PCI_DIV.
823 */
824 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
825
826 /*
827 * Determine EXTBUS_DIV.
828 */
829 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
830
831 /*
832 * Determine OPB_DIV.
833 */
834 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
835
836 /*
837 * Determine the M factor
838 */
839 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
840
841 /*
842 * Determine VCO clock frequency
843 */
stroeseb39392a2004-12-16 18:13:53 +0000844 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
845 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000846
847 /*
848 * Determine CPU clock frequency
849 */
850 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
851 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000852 /*
853 * This is true if FWDVA == FWDVB:
854 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
855 * / pllmr0_ccdv;
856 */
857 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
858 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000859 } else {
860 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
861 }
862
863 /*
864 * Determine PLB clock frequency
865 */
866 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200867
868 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200869
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200870 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
871
Stefan Roesefa8aea22007-10-22 07:33:52 +0200872 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000873}
874
875
876/********************************************
877 * get_OPB_freq
878 * return OPB bus freq in Hz
879 *********************************************/
880ulong get_OPB_freq (void)
881{
882 ulong val = 0;
883
Stefan Roese087dfdb2007-10-21 08:12:41 +0200884 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000885
886 get_sys_info (&sys_info);
887 val = sys_info.freqPLB / sys_info.pllOpbDiv;
888
889 return val;
890}
891
892
893/********************************************
894 * get_PCI_freq
895 * return PCI bus freq in Hz
896 *********************************************/
897ulong get_PCI_freq (void)
898{
899 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200900 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000901
902 get_sys_info (&sys_info);
903 val = sys_info.freqPLB / sys_info.pllPciDiv;
904 return val;
905}
906
Stefan Roesee01bd212007-03-21 13:38:59 +0100907#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200908void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100909{
910 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200911 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100912 unsigned long cpr_primad;
913 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
914 unsigned long primad_cpudv;
915 unsigned long m;
916
917 /*
918 * Read PLL Mode registers
919 */
920 mfcpr(cprplld, cpr_plld);
Stefan Roese273db7e2007-08-13 09:05:33 +0200921 mfcpr(cprpllc, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100922
923 /*
924 * Determine forward divider A
925 */
926 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
927
928 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200929 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100930 */
931 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200932 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100933 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100934
935 /*
936 * Determine FBK_DIV.
937 */
938 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200939 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100940 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100941
942 /*
943 * Read CPR_PRIMAD register
944 */
945 mfcpr(cprprimad, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200946
Stefan Roesee01bd212007-03-21 13:38:59 +0100947 /*
948 * Determine PLB_DIV.
949 */
950 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200951 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100952 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100953
954 /*
955 * Determine EXTBUS_DIV.
956 */
957 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200958 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100959 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100960
961 /*
962 * Determine OPB_DIV.
963 */
964 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200965 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100966 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100967
968 /*
969 * Determine the M factor
970 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200971 if (cpr_pllc & PLLC_SRC_MASK)
972 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
973 else
974 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100975
976 /*
977 * Determine VCO clock frequency
978 */
979 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
980 (unsigned long long)sysClkPeriodPs;
981
982 /*
983 * Determine CPU clock frequency
984 */
985 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200986 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100987 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100988
Stefan Roese273db7e2007-08-13 09:05:33 +0200989 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
990 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100991
992 /*
993 * Determine PLB clock frequency
994 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200995 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
996 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200997
998 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
999 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001000
1001 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roesee01bd212007-03-21 13:38:59 +01001002}
1003
1004/********************************************
1005 * get_OPB_freq
1006 * return OPB bus freq in Hz
1007 *********************************************/
1008ulong get_OPB_freq (void)
1009{
1010 ulong val = 0;
1011
Stefan Roese087dfdb2007-10-21 08:12:41 +02001012 PPC4xx_SYS_INFO sys_info;
Stefan Roesee01bd212007-03-21 13:38:59 +01001013
1014 get_sys_info (&sys_info);
1015 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1016
1017 return val;
1018}
1019
Stefan Roesedbbd1252007-10-05 17:10:59 +02001020#elif defined(CONFIG_405EX)
1021
1022/*
1023 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1024 * We need the specs!!!!
1025 */
1026static unsigned char get_fbdv(unsigned char index)
1027{
1028 unsigned char ret = 0;
1029 /* This is table should be 256 bytes.
1030 * Only take first 52 values.
1031 */
1032 unsigned char fbdv_tb[] = {
1033 0x00, 0xff, 0x7f, 0xfd,
1034 0x7a, 0xf5, 0x6a, 0xd5,
1035 0x2a, 0xd4, 0x29, 0xd3,
1036 0x26, 0xcc, 0x19, 0xb3,
1037 0x67, 0xce, 0x1d, 0xbb,
1038 0x77, 0xee, 0x5d, 0xba,
1039 0x74, 0xe9, 0x52, 0xa5,
1040 0x4b, 0x96, 0x2c, 0xd8,
1041 0x31, 0xe3, 0x46, 0x8d,
1042 0x1b, 0xb7, 0x6f, 0xde,
1043 0x3d, 0xfb, 0x76, 0xed,
1044 0x5a, 0xb5, 0x6b, 0xd6,
1045 0x2d, 0xdb, 0x36, 0xec,
1046
1047 };
1048
1049 if ((index & 0x7f) == 0)
1050 return 1;
1051 while (ret < sizeof (fbdv_tb)) {
1052 if (fbdv_tb[ret] == index)
1053 break;
1054 ret++;
1055 }
1056 ret++;
1057
1058 return ret;
1059}
1060
1061#define PLL_FBK_PLL_LOCAL 0
1062#define PLL_FBK_CPU 1
1063#define PLL_FBK_PERCLK 5
1064
1065void get_sys_info (sys_info_t * sysInfo)
1066{
1067 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1068 unsigned long m = 1;
1069 unsigned int tmp;
1070 unsigned char fwdva[16] = {
1071 1, 2, 14, 9, 4, 11, 16, 13,
1072 12, 5, 6, 15, 10, 7, 8, 3,
1073 };
1074 unsigned char sel, cpudv0, plb2xDiv;
1075
1076 mfcpr(cpr0_plld, tmp);
1077
1078 /*
1079 * Determine forward divider A
1080 */
1081 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1082
1083 /*
1084 * Determine FBK_DIV.
1085 */
1086 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1087
1088 /*
1089 * Determine PLBDV0
1090 */
1091 sysInfo->pllPlbDiv = 2;
1092
1093 /*
1094 * Determine PERDV0
1095 */
1096 mfcpr(cpr0_perd, tmp);
1097 tmp = (tmp >> 24) & 0x03;
1098 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1099
1100 /*
1101 * Determine OPBDV0
1102 */
1103 mfcpr(cpr0_opbd, tmp);
1104 tmp = (tmp >> 24) & 0x03;
1105 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1106
1107 /* Determine PLB2XDV0 */
1108 mfcpr(cpr0_plbd, tmp);
1109 tmp = (tmp >> 16) & 0x07;
1110 plb2xDiv = (tmp == 0) ? 8 : tmp;
1111
1112 /* Determine CPUDV0 */
1113 mfcpr(cpr0_cpud, tmp);
1114 tmp = (tmp >> 24) & 0x07;
1115 cpudv0 = (tmp == 0) ? 8 : tmp;
1116
1117 /* Determine SEL(5:7) in CPR0_PLLC */
1118 mfcpr(cpr0_pllc, tmp);
1119 sel = (tmp >> 24) & 0x07;
1120
1121 /*
1122 * Determine the M factor
1123 * PLL local: M = FBDV
1124 * CPU clock: M = FBDV * FWDVA * CPUDV0
1125 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1126 *
1127 */
1128 switch (sel) {
1129 case PLL_FBK_CPU:
1130 m = sysInfo->pllFwdDiv * cpudv0;
1131 break;
1132 case PLL_FBK_PERCLK:
1133 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1134 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1135 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001136 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001137 break;
1138 default:
1139 printf("%s unknown m\n", __FUNCTION__);
1140 return;
1141
1142 }
1143 m *= sysInfo->pllFbkDiv;
1144
1145 /*
1146 * Determine VCO clock frequency
1147 */
1148 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1149 (unsigned long long)sysClkPeriodPs;
1150
1151 /*
1152 * Determine CPU clock frequency
1153 */
1154 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1155
1156 /*
1157 * Determine PLB clock frequency, ddr1x should be the same
1158 */
1159 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1160 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1161 sysInfo->freqDDR = sysInfo->freqPLB;
1162 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001163 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001164}
1165
1166/********************************************
1167 * get_OPB_freq
1168 * return OPB bus freq in Hz
1169 *********************************************/
1170ulong get_OPB_freq (void)
1171{
1172 ulong val = 0;
1173
Stefan Roese087dfdb2007-10-21 08:12:41 +02001174 PPC4xx_SYS_INFO sys_info;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001175
1176 get_sys_info (&sys_info);
1177 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1178
1179 return val;
1180}
1181
wdenkc6097192002-11-03 00:24:07 +00001182#endif
1183
1184int get_clocks (void)
1185{
Stefan Roesee01bd212007-03-21 13:38:59 +01001186#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1187 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001188 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1189 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001190 sys_info_t sys_info;
1191
1192 get_sys_info (&sys_info);
1193 gd->cpu_clk = sys_info.freqProcessor;
1194 gd->bus_clk = sys_info.freqPLB;
1195
1196#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1197
1198#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001199 gd->cpu_clk = 66000000;
1200 gd->bus_clk = 66000000;
1201#endif
1202 return (0);
1203}
1204
1205
1206/********************************************
1207 * get_bus_freq
1208 * return PLB bus freq in Hz
1209 *********************************************/
1210ulong get_bus_freq (ulong dummy)
1211{
1212 ulong val;
1213
Stefan Roesee01bd212007-03-21 13:38:59 +01001214#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1215 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001216 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1217 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001218 sys_info_t sys_info;
1219
1220 get_sys_info (&sys_info);
1221 val = sys_info.freqPLB;
1222
1223#elif defined(CONFIG_IOP480)
1224
1225 val = 66;
1226
1227#else
1228# error get_bus_freq() not implemented
1229#endif
1230
1231 return val;
1232}