blob: 34bd7214e727e89db6ed3d15bcf1f19e8ec09598 [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
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
Stefan Roese2801b2d2008-03-11 15:05:50 +0100208#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
209static u8 pll_fwdv_multi_bits[] = {
210 /* values for: 1 - 16 */
211 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
212 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
213};
214
215u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
216{
217 u32 index;
218
219 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
220 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
221 return index + 1;
222
223 return 0;
224}
225
226static u8 pll_fbdv_multi_bits[] = {
227 /* values for: 1 - 100 */
228 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
229 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
230 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
231 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
232 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
233 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
234 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
235 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
236 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
237 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
238 /* values for: 101 - 200 */
239 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
240 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchellb9bbefc2008-05-07 09:00:23 -0700241 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roese2801b2d2008-03-11 15:05:50 +0100242 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
243 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
244 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
245 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
246 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
247 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
248 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
249 /* values for: 201 - 255 */
250 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
251 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
252 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
253 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
254 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
255 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
256};
257
258u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
259{
260 u32 index;
261
262 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
263 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
264 return index + 1;
265
266 return 0;
267}
268
269/*
270 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
271 * with latest EAS
272 */
273void get_sys_info (sys_info_t * sysInfo)
274{
275 unsigned long strp0;
276 unsigned long strp1;
277 unsigned long temp;
278 unsigned long m;
279 unsigned long plbedv0;
280
281 /* Extract configured divisors */
282 mfsdr(sdr_sdstp0, strp0);
283 mfsdr(sdr_sdstp1, strp1);
284
285 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
286 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
287
288 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
289 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
290
291 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
292 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
293
294 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
295 sysInfo->pllOpbDiv = temp ? temp : 4;
296
297 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
298 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
299 sysInfo->pllExtBusDiv = temp ? temp : 4;
300
301 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
302 plbedv0 = temp ? temp: 8;
303
304 /* Calculate 'M' based on feedback source */
305 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
306 if (temp == 0) {
307 /* PLL internal feedback */
308 m = sysInfo->pllFbkDiv;
309 } else {
310 /* PLL PerClk feedback */
311 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
312 sysInfo->pllExtBusDiv;
313 }
314
315 /* Now calculate the individual clocks */
316 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
317 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
318 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
319 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
320 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
321 sysInfo->freqDDR = sysInfo->freqPLB;
322 sysInfo->freqUART = sysInfo->freqPLB;
323
324 return;
325}
326
327#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200328 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200329void get_sys_info (sys_info_t *sysInfo)
330{
331 unsigned long temp;
332 unsigned long reg;
333 unsigned long lfdiv;
334 unsigned long m;
335 unsigned long prbdv0;
336 /*
337 WARNING: ASSUMES the following:
338 ENG=1
339 PRADV0=1
340 PRBDV0=1
341 */
342
343 /* Decode CPR0_PLLD0 for divisors */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200344 mfcpr(clk_plld, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200345 temp = (reg & PLLD_FWDVA_MASK) >> 16;
346 sysInfo->pllFwdDivA = temp ? temp : 16;
347 temp = (reg & PLLD_FWDVB_MASK) >> 8;
348 sysInfo->pllFwdDivB = temp ? temp: 8 ;
349 temp = (reg & PLLD_FBDV_MASK) >> 24;
350 sysInfo->pllFbkDiv = temp ? temp : 32;
351 lfdiv = reg & PLLD_LFBDV_MASK;
352
Stefan Roese087dfdb2007-10-21 08:12:41 +0200353 mfcpr(clk_opbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200354 temp = (reg & OPBDDV_MASK) >> 24;
355 sysInfo->pllOpbDiv = temp ? temp : 4;
356
Stefan Roese087dfdb2007-10-21 08:12:41 +0200357 mfcpr(clk_perd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200358 temp = (reg & PERDV_MASK) >> 24;
359 sysInfo->pllExtBusDiv = temp ? temp : 8;
360
Stefan Roese087dfdb2007-10-21 08:12:41 +0200361 mfcpr(clk_primbd, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200362 temp = (reg & PRBDV_MASK) >> 24;
363 prbdv0 = temp ? temp : 8;
364
Stefan Roese087dfdb2007-10-21 08:12:41 +0200365 mfcpr(clk_spcid, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200366 temp = (reg & SPCID_MASK) >> 24;
367 sysInfo->pllPciDiv = temp ? temp : 4;
368
369 /* Calculate 'M' based on feedback source */
370 mfsdr(sdr_sdstp0, reg);
371 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
372 if (temp == 0) { /* PLL output */
373 /* Figure which pll to use */
Stefan Roese087dfdb2007-10-21 08:12:41 +0200374 mfcpr(clk_pllc, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200375 temp = (reg & PLLC_SRC_MASK) >> 29;
376 if (!temp) /* PLLOUTA */
377 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
378 else /* PLLOUTB */
379 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
380 }
381 else if (temp == 1) /* CPU output */
382 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
383 else /* PerClk */
384 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
385
386 /* Now calculate the individual clocks */
387 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
388 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
389 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
390 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200391 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200392 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200393 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200394
395 /* Figure which timer source to use */
396 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
397 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
398 if (CONFIG_SYS_CLK_FREQ > temp)
399 sysInfo->freqTmrClk = temp;
400 else
401 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
402 }
403 else /* Internal clock */
404 sysInfo->freqTmrClk = sysInfo->freqProcessor;
405}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200406
Stefan Roesec157d8e2005-08-01 16:41:48 +0200407/********************************************
408 * get_PCI_freq
409 * return PCI bus freq in Hz
410 *********************************************/
411ulong get_PCI_freq (void)
412{
413 sys_info_t sys_info;
414 get_sys_info (&sys_info);
415 return sys_info.freqPCI;
416}
417
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200418#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
wdenkc6097192002-11-03 00:24:07 +0000419void get_sys_info (sys_info_t * sysInfo)
420{
421 unsigned long strp0;
422 unsigned long temp;
423 unsigned long m;
424
425 /* Extract configured divisors */
426 strp0 = mfdcr( cpc0_strp0 );
427 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
428 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
429 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
430 sysInfo->pllFbkDiv = temp ? temp : 16;
431 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
432 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
433
434 /* Calculate 'M' based on feedback source */
435 if( strp0 & PLLSYS0_EXTSL_MASK )
436 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
437 else
438 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
439
440 /* Now calculate the individual clocks */
441 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
442 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
443 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200444 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
445 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000446 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200447 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200448 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000449}
wdenkba56f622004-02-06 23:19:44 +0000450#else
451void get_sys_info (sys_info_t * sysInfo)
452{
453 unsigned long strp0;
454 unsigned long strp1;
455 unsigned long temp;
456 unsigned long temp1;
457 unsigned long lfdiv;
458 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000459 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000460
Stefan Roese4745aca2007-02-20 10:57:08 +0100461#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200462 unsigned long sys_freq;
463 unsigned long sys_per=0;
464 unsigned long msr;
465 unsigned long pci_clock_per;
466 unsigned long sdr_ddrpll;
467
468 /*-------------------------------------------------------------------------+
469 | Get the system clock period.
470 +-------------------------------------------------------------------------*/
471 sys_per = determine_sysper();
472
473 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
474
475 /*-------------------------------------------------------------------------+
476 | Calculate the system clock speed from the period.
477 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100478 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200479#endif
480
wdenkba56f622004-02-06 23:19:44 +0000481 /* Extract configured divisors */
482 mfsdr( sdr_sdstp0,strp0 );
483 mfsdr( sdr_sdstp1,strp1 );
484
485 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
486 sysInfo->pllFwdDivA = temp ? temp : 16 ;
487 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
488 sysInfo->pllFwdDivB = temp ? temp: 8 ;
489 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
490 sysInfo->pllFbkDiv = temp ? temp : 32;
491 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
492 sysInfo->pllOpbDiv = temp ? temp : 4;
493 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
494 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000495 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000496
497 /* Calculate 'M' based on feedback source */
498 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
499 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
500 lfdiv = temp1 ? temp1 : 64;
501 if (temp == 0) { /* PLL output */
502 /* Figure which pll to use */
503 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
504 if (!temp)
505 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
506 else
507 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
508 }
509 else if (temp == 1) /* CPU output */
510 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
511 else /* PerClk */
512 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
513
514 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100515#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200516 sysInfo->freqVCOMhz = (m * sys_freq) ;
517#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100518 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200519#endif
wdenkba56f622004-02-06 23:19:44 +0000520 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000521 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000522 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200523 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000524
Stefan Roese4745aca2007-02-20 10:57:08 +0100525#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200526 /* Determine PCI Clock Period */
527 pci_clock_per = determine_pci_clock_per();
528 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
529 mfsdr(sdr_ddr0, sdr_ddrpll);
530 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
531#endif
532
Stefan Roesefa8aea22007-10-22 07:33:52 +0200533 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200534}
535
536#endif
537
Stefan Roese4745aca2007-02-20 10:57:08 +0100538#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200539unsigned long determine_sysper(void)
540{
541 unsigned int fpga_clocking_reg;
542 unsigned int master_clock_selection;
543 unsigned long master_clock_per = 0;
544 unsigned long fb_div_selection;
545 unsigned int vco_div_reg_value;
546 unsigned long vco_div_selection;
547 unsigned long sys_per = 0;
548 int extClkVal;
549
550 /*-------------------------------------------------------------------------+
551 | Read FPGA reg 0 and reg 1 to get FPGA reg information
552 +-------------------------------------------------------------------------*/
553 fpga_clocking_reg = in16(FPGA_REG16);
554
555
556 /* Determine Master Clock Source Selection */
557 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
558
559 switch(master_clock_selection) {
560 case FPGA_REG16_MASTER_CLK_66_66:
561 master_clock_per = PERIOD_66_66MHZ;
562 break;
563 case FPGA_REG16_MASTER_CLK_50:
564 master_clock_per = PERIOD_50_00MHZ;
565 break;
566 case FPGA_REG16_MASTER_CLK_33_33:
567 master_clock_per = PERIOD_33_33MHZ;
568 break;
569 case FPGA_REG16_MASTER_CLK_25:
570 master_clock_per = PERIOD_25_00MHZ;
571 break;
572 case FPGA_REG16_MASTER_CLK_EXT:
573 if ((extClkVal==EXTCLK_33_33)
574 && (extClkVal==EXTCLK_50)
575 && (extClkVal==EXTCLK_66_66)
576 && (extClkVal==EXTCLK_83)) {
577 /* calculate master clock period from external clock value */
578 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
579 } else {
580 /* Unsupported */
581 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
582 hang();
583 }
584 break;
585 default:
586 /* Unsupported */
587 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
588 hang();
589 break;
590 }
591
592 /* Determine FB divisors values */
593 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
594 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
595 fb_div_selection = FPGA_FB_DIV_6;
596 else
597 fb_div_selection = FPGA_FB_DIV_12;
598 } else {
599 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
600 fb_div_selection = FPGA_FB_DIV_10;
601 else
602 fb_div_selection = FPGA_FB_DIV_20;
603 }
604
605 /* Determine VCO divisors values */
606 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
607
608 switch(vco_div_reg_value) {
609 case FPGA_REG16_VCO_DIV_4:
610 vco_div_selection = FPGA_VCO_DIV_4;
611 break;
612 case FPGA_REG16_VCO_DIV_6:
613 vco_div_selection = FPGA_VCO_DIV_6;
614 break;
615 case FPGA_REG16_VCO_DIV_8:
616 vco_div_selection = FPGA_VCO_DIV_8;
617 break;
618 case FPGA_REG16_VCO_DIV_10:
619 default:
620 vco_div_selection = FPGA_VCO_DIV_10;
621 break;
622 }
623
624 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
625 switch(master_clock_per) {
626 case PERIOD_25_00MHZ:
627 if (fb_div_selection == FPGA_FB_DIV_12) {
628 if (vco_div_selection == FPGA_VCO_DIV_4)
629 sys_per = PERIOD_75_00MHZ;
630 if (vco_div_selection == FPGA_VCO_DIV_6)
631 sys_per = PERIOD_50_00MHZ;
632 }
633 break;
634 case PERIOD_33_33MHZ:
635 if (fb_div_selection == FPGA_FB_DIV_6) {
636 if (vco_div_selection == FPGA_VCO_DIV_4)
637 sys_per = PERIOD_50_00MHZ;
638 if (vco_div_selection == FPGA_VCO_DIV_6)
639 sys_per = PERIOD_33_33MHZ;
640 }
641 if (fb_div_selection == FPGA_FB_DIV_10) {
642 if (vco_div_selection == FPGA_VCO_DIV_4)
643 sys_per = PERIOD_83_33MHZ;
644 if (vco_div_selection == FPGA_VCO_DIV_10)
645 sys_per = PERIOD_33_33MHZ;
646 }
647 if (fb_div_selection == FPGA_FB_DIV_12) {
648 if (vco_div_selection == FPGA_VCO_DIV_4)
649 sys_per = PERIOD_100_00MHZ;
650 if (vco_div_selection == FPGA_VCO_DIV_6)
651 sys_per = PERIOD_66_66MHZ;
652 if (vco_div_selection == FPGA_VCO_DIV_8)
653 sys_per = PERIOD_50_00MHZ;
654 }
655 break;
656 case PERIOD_50_00MHZ:
657 if (fb_div_selection == FPGA_FB_DIV_6) {
658 if (vco_div_selection == FPGA_VCO_DIV_4)
659 sys_per = PERIOD_75_00MHZ;
660 if (vco_div_selection == FPGA_VCO_DIV_6)
661 sys_per = PERIOD_50_00MHZ;
662 }
663 if (fb_div_selection == FPGA_FB_DIV_10) {
664 if (vco_div_selection == FPGA_VCO_DIV_6)
665 sys_per = PERIOD_83_33MHZ;
666 if (vco_div_selection == FPGA_VCO_DIV_10)
667 sys_per = PERIOD_50_00MHZ;
668 }
669 if (fb_div_selection == FPGA_FB_DIV_12) {
670 if (vco_div_selection == FPGA_VCO_DIV_6)
671 sys_per = PERIOD_100_00MHZ;
672 if (vco_div_selection == FPGA_VCO_DIV_8)
673 sys_per = PERIOD_75_00MHZ;
674 }
675 break;
676 case PERIOD_66_66MHZ:
677 if (fb_div_selection == FPGA_FB_DIV_6) {
678 if (vco_div_selection == FPGA_VCO_DIV_4)
679 sys_per = PERIOD_100_00MHZ;
680 if (vco_div_selection == FPGA_VCO_DIV_6)
681 sys_per = PERIOD_66_66MHZ;
682 if (vco_div_selection == FPGA_VCO_DIV_8)
683 sys_per = PERIOD_50_00MHZ;
684 }
685 if (fb_div_selection == FPGA_FB_DIV_10) {
686 if (vco_div_selection == FPGA_VCO_DIV_8)
687 sys_per = PERIOD_83_33MHZ;
688 if (vco_div_selection == FPGA_VCO_DIV_10)
689 sys_per = PERIOD_66_66MHZ;
690 }
691 if (fb_div_selection == FPGA_FB_DIV_12) {
692 if (vco_div_selection == FPGA_VCO_DIV_8)
693 sys_per = PERIOD_100_00MHZ;
694 }
695 break;
696 default:
697 break;
698 }
699
700 if (sys_per == 0) {
701 /* Other combinations are not supported */
702 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
703 hang();
704 }
705 } else {
706 /* calcul system clock without cheking */
707 /* if engineering option clock no check is selected */
708 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
709 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
710 }
711
712 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200713}
714
715/*-------------------------------------------------------------------------+
716| determine_pci_clock_per.
717+-------------------------------------------------------------------------*/
718unsigned long determine_pci_clock_per(void)
719{
720 unsigned long pci_clock_selection, pci_period;
721
722 /*-------------------------------------------------------------------------+
723 | Read FPGA reg 6 to get PCI 0 FPGA reg information
724 +-------------------------------------------------------------------------*/
725 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
726
727
728 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
729
730 switch (pci_clock_selection) {
731 case FPGA_REG16_PCI0_CLK_133_33:
732 pci_period = PERIOD_133_33MHZ;
733 break;
734 case FPGA_REG16_PCI0_CLK_100:
735 pci_period = PERIOD_100_00MHZ;
736 break;
737 case FPGA_REG16_PCI0_CLK_66_66:
738 pci_period = PERIOD_66_66MHZ;
739 break;
740 default:
741 pci_period = PERIOD_33_33MHZ;;
742 break;
743 }
744
745 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000746}
747#endif
wdenkc6097192002-11-03 00:24:07 +0000748
749ulong get_OPB_freq (void)
750{
751
752 sys_info_t sys_info;
753 get_sys_info (&sys_info);
754 return sys_info.freqOPB;
755}
756
Michal Simek9fea65a2008-06-24 09:54:09 +0200757#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000758extern void get_sys_info (sys_info_t * sysInfo);
759extern ulong get_PCI_freq (void);
760
Wolfgang Denk7521af12005-10-09 01:04:33 +0200761#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200762void get_sys_info (sys_info_t * sysInfo)
763{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200764 sysInfo->freqProcessor = 240 * 1000 * 1000;
765 sysInfo->freqPLB = 80 * 1000 * 1000;
766 sysInfo->freqPCI = 33 * 1000 * 1000;
767}
768
wdenkc6097192002-11-03 00:24:07 +0000769#elif defined(CONFIG_405)
770
Stefan Roesefa8aea22007-10-22 07:33:52 +0200771void get_sys_info (sys_info_t * sysInfo)
772{
wdenkc6097192002-11-03 00:24:07 +0000773 sysInfo->freqVCOMhz=3125000;
774 sysInfo->freqProcessor=12*1000*1000;
775 sysInfo->freqPLB=50*1000*1000;
776 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000777}
778
stroeseb867d702003-05-23 11:18:02 +0000779#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200780void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000781{
782 unsigned long pllmr0;
783 unsigned long pllmr1;
784 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
785 unsigned long m;
786 unsigned long pllmr0_ccdv;
787
788 /*
789 * Read PLL Mode registers
790 */
791 pllmr0 = mfdcr (cpc0_pllmr0);
792 pllmr1 = mfdcr (cpc0_pllmr1);
793
794 /*
795 * Determine forward divider A
796 */
797 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
798
799 /*
800 * Determine forward divider B (should be equal to A)
801 */
802 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
803
804 /*
805 * Determine FBK_DIV.
806 */
807 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200808 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000809 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000810
811 /*
812 * Determine PLB_DIV.
813 */
814 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
815
816 /*
817 * Determine PCI_DIV.
818 */
819 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
820
821 /*
822 * Determine EXTBUS_DIV.
823 */
824 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
825
826 /*
827 * Determine OPB_DIV.
828 */
829 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
830
831 /*
832 * Determine the M factor
833 */
834 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
835
836 /*
837 * Determine VCO clock frequency
838 */
stroeseb39392a2004-12-16 18:13:53 +0000839 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
840 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000841
842 /*
843 * Determine CPU clock frequency
844 */
845 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
846 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000847 /*
848 * This is true if FWDVA == FWDVB:
849 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
850 * / pllmr0_ccdv;
851 */
852 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
853 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000854 } else {
855 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
856 }
857
858 /*
859 * Determine PLB clock frequency
860 */
861 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200862
863 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200864
865 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000866}
867
868
869/********************************************
870 * get_OPB_freq
871 * return OPB bus freq in Hz
872 *********************************************/
873ulong get_OPB_freq (void)
874{
875 ulong val = 0;
876
Stefan Roese087dfdb2007-10-21 08:12:41 +0200877 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000878
879 get_sys_info (&sys_info);
880 val = sys_info.freqPLB / sys_info.pllOpbDiv;
881
882 return val;
883}
884
885
886/********************************************
887 * get_PCI_freq
888 * return PCI bus freq in Hz
889 *********************************************/
890ulong get_PCI_freq (void)
891{
892 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200893 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000894
895 get_sys_info (&sys_info);
896 val = sys_info.freqPLB / sys_info.pllPciDiv;
897 return val;
898}
899
Stefan Roesee01bd212007-03-21 13:38:59 +0100900#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200901void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100902{
903 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200904 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100905 unsigned long cpr_primad;
906 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
907 unsigned long primad_cpudv;
908 unsigned long m;
909
910 /*
911 * Read PLL Mode registers
912 */
913 mfcpr(cprplld, cpr_plld);
Stefan Roese273db7e2007-08-13 09:05:33 +0200914 mfcpr(cprpllc, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100915
916 /*
917 * Determine forward divider A
918 */
919 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
920
921 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200922 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100923 */
924 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200925 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100926 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100927
928 /*
929 * Determine FBK_DIV.
930 */
931 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200932 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100933 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100934
935 /*
936 * Read CPR_PRIMAD register
937 */
938 mfcpr(cprprimad, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200939
Stefan Roesee01bd212007-03-21 13:38:59 +0100940 /*
941 * Determine PLB_DIV.
942 */
943 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200944 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100945 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100946
947 /*
948 * Determine EXTBUS_DIV.
949 */
950 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200951 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100952 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100953
954 /*
955 * Determine OPB_DIV.
956 */
957 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200958 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100959 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100960
961 /*
962 * Determine the M factor
963 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200964 if (cpr_pllc & PLLC_SRC_MASK)
965 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
966 else
967 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100968
969 /*
970 * Determine VCO clock frequency
971 */
972 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
973 (unsigned long long)sysClkPeriodPs;
974
975 /*
976 * Determine CPU clock frequency
977 */
978 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200979 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100980 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100981
Stefan Roese273db7e2007-08-13 09:05:33 +0200982 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
983 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100984
985 /*
986 * Determine PLB clock frequency
987 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200988 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
989 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200990
991 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
992 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200993
994 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roesee01bd212007-03-21 13:38:59 +0100995}
996
997/********************************************
998 * get_OPB_freq
999 * return OPB bus freq in Hz
1000 *********************************************/
1001ulong get_OPB_freq (void)
1002{
1003 ulong val = 0;
1004
Stefan Roese087dfdb2007-10-21 08:12:41 +02001005 PPC4xx_SYS_INFO sys_info;
Stefan Roesee01bd212007-03-21 13:38:59 +01001006
1007 get_sys_info (&sys_info);
1008 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1009
1010 return val;
1011}
1012
Stefan Roesedbbd1252007-10-05 17:10:59 +02001013#elif defined(CONFIG_405EX)
1014
1015/*
1016 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1017 * We need the specs!!!!
1018 */
1019static unsigned char get_fbdv(unsigned char index)
1020{
1021 unsigned char ret = 0;
1022 /* This is table should be 256 bytes.
1023 * Only take first 52 values.
1024 */
1025 unsigned char fbdv_tb[] = {
1026 0x00, 0xff, 0x7f, 0xfd,
1027 0x7a, 0xf5, 0x6a, 0xd5,
1028 0x2a, 0xd4, 0x29, 0xd3,
1029 0x26, 0xcc, 0x19, 0xb3,
1030 0x67, 0xce, 0x1d, 0xbb,
1031 0x77, 0xee, 0x5d, 0xba,
1032 0x74, 0xe9, 0x52, 0xa5,
1033 0x4b, 0x96, 0x2c, 0xd8,
1034 0x31, 0xe3, 0x46, 0x8d,
1035 0x1b, 0xb7, 0x6f, 0xde,
1036 0x3d, 0xfb, 0x76, 0xed,
1037 0x5a, 0xb5, 0x6b, 0xd6,
1038 0x2d, 0xdb, 0x36, 0xec,
1039
1040 };
1041
1042 if ((index & 0x7f) == 0)
1043 return 1;
1044 while (ret < sizeof (fbdv_tb)) {
1045 if (fbdv_tb[ret] == index)
1046 break;
1047 ret++;
1048 }
1049 ret++;
1050
1051 return ret;
1052}
1053
1054#define PLL_FBK_PLL_LOCAL 0
1055#define PLL_FBK_CPU 1
1056#define PLL_FBK_PERCLK 5
1057
1058void get_sys_info (sys_info_t * sysInfo)
1059{
1060 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1061 unsigned long m = 1;
1062 unsigned int tmp;
1063 unsigned char fwdva[16] = {
1064 1, 2, 14, 9, 4, 11, 16, 13,
1065 12, 5, 6, 15, 10, 7, 8, 3,
1066 };
1067 unsigned char sel, cpudv0, plb2xDiv;
1068
1069 mfcpr(cpr0_plld, tmp);
1070
1071 /*
1072 * Determine forward divider A
1073 */
1074 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1075
1076 /*
1077 * Determine FBK_DIV.
1078 */
1079 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1080
1081 /*
1082 * Determine PLBDV0
1083 */
1084 sysInfo->pllPlbDiv = 2;
1085
1086 /*
1087 * Determine PERDV0
1088 */
1089 mfcpr(cpr0_perd, tmp);
1090 tmp = (tmp >> 24) & 0x03;
1091 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1092
1093 /*
1094 * Determine OPBDV0
1095 */
1096 mfcpr(cpr0_opbd, tmp);
1097 tmp = (tmp >> 24) & 0x03;
1098 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1099
1100 /* Determine PLB2XDV0 */
1101 mfcpr(cpr0_plbd, tmp);
1102 tmp = (tmp >> 16) & 0x07;
1103 plb2xDiv = (tmp == 0) ? 8 : tmp;
1104
1105 /* Determine CPUDV0 */
1106 mfcpr(cpr0_cpud, tmp);
1107 tmp = (tmp >> 24) & 0x07;
1108 cpudv0 = (tmp == 0) ? 8 : tmp;
1109
1110 /* Determine SEL(5:7) in CPR0_PLLC */
1111 mfcpr(cpr0_pllc, tmp);
1112 sel = (tmp >> 24) & 0x07;
1113
1114 /*
1115 * Determine the M factor
1116 * PLL local: M = FBDV
1117 * CPU clock: M = FBDV * FWDVA * CPUDV0
1118 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1119 *
1120 */
1121 switch (sel) {
1122 case PLL_FBK_CPU:
1123 m = sysInfo->pllFwdDiv * cpudv0;
1124 break;
1125 case PLL_FBK_PERCLK:
1126 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1127 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1128 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001129 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001130 break;
1131 default:
1132 printf("%s unknown m\n", __FUNCTION__);
1133 return;
1134
1135 }
1136 m *= sysInfo->pllFbkDiv;
1137
1138 /*
1139 * Determine VCO clock frequency
1140 */
1141 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1142 (unsigned long long)sysClkPeriodPs;
1143
1144 /*
1145 * Determine CPU clock frequency
1146 */
1147 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1148
1149 /*
1150 * Determine PLB clock frequency, ddr1x should be the same
1151 */
1152 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1153 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1154 sysInfo->freqDDR = sysInfo->freqPLB;
1155 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001156 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001157}
1158
1159/********************************************
1160 * get_OPB_freq
1161 * return OPB bus freq in Hz
1162 *********************************************/
1163ulong get_OPB_freq (void)
1164{
1165 ulong val = 0;
1166
Stefan Roese087dfdb2007-10-21 08:12:41 +02001167 PPC4xx_SYS_INFO sys_info;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001168
1169 get_sys_info (&sys_info);
1170 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1171
1172 return val;
1173}
1174
wdenkc6097192002-11-03 00:24:07 +00001175#endif
1176
1177int get_clocks (void)
1178{
Stefan Roesee01bd212007-03-21 13:38:59 +01001179#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1180 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001181 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1182 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001183 sys_info_t sys_info;
1184
1185 get_sys_info (&sys_info);
1186 gd->cpu_clk = sys_info.freqProcessor;
1187 gd->bus_clk = sys_info.freqPLB;
1188
1189#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1190
1191#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001192 gd->cpu_clk = 66000000;
1193 gd->bus_clk = 66000000;
1194#endif
1195 return (0);
1196}
1197
1198
1199/********************************************
1200 * get_bus_freq
1201 * return PLB bus freq in Hz
1202 *********************************************/
1203ulong get_bus_freq (ulong dummy)
1204{
1205 ulong val;
1206
Stefan Roesee01bd212007-03-21 13:38:59 +01001207#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1208 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001209 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1210 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001211 sys_info_t sys_info;
1212
1213 get_sys_info (&sys_info);
1214 val = sys_info.freqPLB;
1215
1216#elif defined(CONFIG_IOP480)
1217
1218 val = 66;
1219
1220#else
1221# error get_bus_freq() not implemented
1222#endif
1223
1224 return val;
1225}