blob: b86b6dece66519ad06145213619567a3bdd7dc68 [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
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
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200419#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE)
wdenkc6097192002-11-03 00:24:07 +0000420void get_sys_info (sys_info_t * sysInfo)
421{
422 unsigned long strp0;
423 unsigned long temp;
424 unsigned long m;
425
426 /* Extract configured divisors */
427 strp0 = mfdcr( cpc0_strp0 );
428 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
429 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
430 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
431 sysInfo->pllFbkDiv = temp ? temp : 16;
432 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
433 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
434
435 /* Calculate 'M' based on feedback source */
436 if( strp0 & PLLSYS0_EXTSL_MASK )
437 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
438 else
439 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
440
441 /* Now calculate the individual clocks */
442 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
443 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
444 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200445 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
446 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000447 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200448 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200449 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000450}
wdenkba56f622004-02-06 23:19:44 +0000451#else
452void get_sys_info (sys_info_t * sysInfo)
453{
454 unsigned long strp0;
455 unsigned long strp1;
456 unsigned long temp;
457 unsigned long temp1;
458 unsigned long lfdiv;
459 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000460 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000461
Stefan Roese4745aca2007-02-20 10:57:08 +0100462#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200463 unsigned long sys_freq;
464 unsigned long sys_per=0;
465 unsigned long msr;
466 unsigned long pci_clock_per;
467 unsigned long sdr_ddrpll;
468
469 /*-------------------------------------------------------------------------+
470 | Get the system clock period.
471 +-------------------------------------------------------------------------*/
472 sys_per = determine_sysper();
473
474 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
475
476 /*-------------------------------------------------------------------------+
477 | Calculate the system clock speed from the period.
478 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100479 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200480#endif
481
wdenkba56f622004-02-06 23:19:44 +0000482 /* Extract configured divisors */
483 mfsdr( sdr_sdstp0,strp0 );
484 mfsdr( sdr_sdstp1,strp1 );
485
486 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
487 sysInfo->pllFwdDivA = temp ? temp : 16 ;
488 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
489 sysInfo->pllFwdDivB = temp ? temp: 8 ;
490 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
491 sysInfo->pllFbkDiv = temp ? temp : 32;
492 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
493 sysInfo->pllOpbDiv = temp ? temp : 4;
494 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
495 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000496 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000497
498 /* Calculate 'M' based on feedback source */
499 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
500 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
501 lfdiv = temp1 ? temp1 : 64;
502 if (temp == 0) { /* PLL output */
503 /* Figure which pll to use */
504 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
505 if (!temp)
506 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
507 else
508 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
509 }
510 else if (temp == 1) /* CPU output */
511 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
512 else /* PerClk */
513 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
514
515 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100516#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200517 sysInfo->freqVCOMhz = (m * sys_freq) ;
518#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100519 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200520#endif
wdenkba56f622004-02-06 23:19:44 +0000521 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000522 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000523 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200524 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000525
Stefan Roese4745aca2007-02-20 10:57:08 +0100526#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200527 /* Determine PCI Clock Period */
528 pci_clock_per = determine_pci_clock_per();
529 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
530 mfsdr(sdr_ddr0, sdr_ddrpll);
531 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
532#endif
533
Stefan Roesefa8aea22007-10-22 07:33:52 +0200534 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200535}
536
537#endif
538
Stefan Roese4745aca2007-02-20 10:57:08 +0100539#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200540unsigned long determine_sysper(void)
541{
542 unsigned int fpga_clocking_reg;
543 unsigned int master_clock_selection;
544 unsigned long master_clock_per = 0;
545 unsigned long fb_div_selection;
546 unsigned int vco_div_reg_value;
547 unsigned long vco_div_selection;
548 unsigned long sys_per = 0;
549 int extClkVal;
550
551 /*-------------------------------------------------------------------------+
552 | Read FPGA reg 0 and reg 1 to get FPGA reg information
553 +-------------------------------------------------------------------------*/
554 fpga_clocking_reg = in16(FPGA_REG16);
555
556
557 /* Determine Master Clock Source Selection */
558 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
559
560 switch(master_clock_selection) {
561 case FPGA_REG16_MASTER_CLK_66_66:
562 master_clock_per = PERIOD_66_66MHZ;
563 break;
564 case FPGA_REG16_MASTER_CLK_50:
565 master_clock_per = PERIOD_50_00MHZ;
566 break;
567 case FPGA_REG16_MASTER_CLK_33_33:
568 master_clock_per = PERIOD_33_33MHZ;
569 break;
570 case FPGA_REG16_MASTER_CLK_25:
571 master_clock_per = PERIOD_25_00MHZ;
572 break;
573 case FPGA_REG16_MASTER_CLK_EXT:
574 if ((extClkVal==EXTCLK_33_33)
575 && (extClkVal==EXTCLK_50)
576 && (extClkVal==EXTCLK_66_66)
577 && (extClkVal==EXTCLK_83)) {
578 /* calculate master clock period from external clock value */
579 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
580 } else {
581 /* Unsupported */
582 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
583 hang();
584 }
585 break;
586 default:
587 /* Unsupported */
588 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
589 hang();
590 break;
591 }
592
593 /* Determine FB divisors values */
594 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
595 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
596 fb_div_selection = FPGA_FB_DIV_6;
597 else
598 fb_div_selection = FPGA_FB_DIV_12;
599 } else {
600 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
601 fb_div_selection = FPGA_FB_DIV_10;
602 else
603 fb_div_selection = FPGA_FB_DIV_20;
604 }
605
606 /* Determine VCO divisors values */
607 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
608
609 switch(vco_div_reg_value) {
610 case FPGA_REG16_VCO_DIV_4:
611 vco_div_selection = FPGA_VCO_DIV_4;
612 break;
613 case FPGA_REG16_VCO_DIV_6:
614 vco_div_selection = FPGA_VCO_DIV_6;
615 break;
616 case FPGA_REG16_VCO_DIV_8:
617 vco_div_selection = FPGA_VCO_DIV_8;
618 break;
619 case FPGA_REG16_VCO_DIV_10:
620 default:
621 vco_div_selection = FPGA_VCO_DIV_10;
622 break;
623 }
624
625 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
626 switch(master_clock_per) {
627 case PERIOD_25_00MHZ:
628 if (fb_div_selection == FPGA_FB_DIV_12) {
629 if (vco_div_selection == FPGA_VCO_DIV_4)
630 sys_per = PERIOD_75_00MHZ;
631 if (vco_div_selection == FPGA_VCO_DIV_6)
632 sys_per = PERIOD_50_00MHZ;
633 }
634 break;
635 case PERIOD_33_33MHZ:
636 if (fb_div_selection == FPGA_FB_DIV_6) {
637 if (vco_div_selection == FPGA_VCO_DIV_4)
638 sys_per = PERIOD_50_00MHZ;
639 if (vco_div_selection == FPGA_VCO_DIV_6)
640 sys_per = PERIOD_33_33MHZ;
641 }
642 if (fb_div_selection == FPGA_FB_DIV_10) {
643 if (vco_div_selection == FPGA_VCO_DIV_4)
644 sys_per = PERIOD_83_33MHZ;
645 if (vco_div_selection == FPGA_VCO_DIV_10)
646 sys_per = PERIOD_33_33MHZ;
647 }
648 if (fb_div_selection == FPGA_FB_DIV_12) {
649 if (vco_div_selection == FPGA_VCO_DIV_4)
650 sys_per = PERIOD_100_00MHZ;
651 if (vco_div_selection == FPGA_VCO_DIV_6)
652 sys_per = PERIOD_66_66MHZ;
653 if (vco_div_selection == FPGA_VCO_DIV_8)
654 sys_per = PERIOD_50_00MHZ;
655 }
656 break;
657 case PERIOD_50_00MHZ:
658 if (fb_div_selection == FPGA_FB_DIV_6) {
659 if (vco_div_selection == FPGA_VCO_DIV_4)
660 sys_per = PERIOD_75_00MHZ;
661 if (vco_div_selection == FPGA_VCO_DIV_6)
662 sys_per = PERIOD_50_00MHZ;
663 }
664 if (fb_div_selection == FPGA_FB_DIV_10) {
665 if (vco_div_selection == FPGA_VCO_DIV_6)
666 sys_per = PERIOD_83_33MHZ;
667 if (vco_div_selection == FPGA_VCO_DIV_10)
668 sys_per = PERIOD_50_00MHZ;
669 }
670 if (fb_div_selection == FPGA_FB_DIV_12) {
671 if (vco_div_selection == FPGA_VCO_DIV_6)
672 sys_per = PERIOD_100_00MHZ;
673 if (vco_div_selection == FPGA_VCO_DIV_8)
674 sys_per = PERIOD_75_00MHZ;
675 }
676 break;
677 case PERIOD_66_66MHZ:
678 if (fb_div_selection == FPGA_FB_DIV_6) {
679 if (vco_div_selection == FPGA_VCO_DIV_4)
680 sys_per = PERIOD_100_00MHZ;
681 if (vco_div_selection == FPGA_VCO_DIV_6)
682 sys_per = PERIOD_66_66MHZ;
683 if (vco_div_selection == FPGA_VCO_DIV_8)
684 sys_per = PERIOD_50_00MHZ;
685 }
686 if (fb_div_selection == FPGA_FB_DIV_10) {
687 if (vco_div_selection == FPGA_VCO_DIV_8)
688 sys_per = PERIOD_83_33MHZ;
689 if (vco_div_selection == FPGA_VCO_DIV_10)
690 sys_per = PERIOD_66_66MHZ;
691 }
692 if (fb_div_selection == FPGA_FB_DIV_12) {
693 if (vco_div_selection == FPGA_VCO_DIV_8)
694 sys_per = PERIOD_100_00MHZ;
695 }
696 break;
697 default:
698 break;
699 }
700
701 if (sys_per == 0) {
702 /* Other combinations are not supported */
703 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
704 hang();
705 }
706 } else {
707 /* calcul system clock without cheking */
708 /* if engineering option clock no check is selected */
709 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
710 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
711 }
712
713 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200714}
715
716/*-------------------------------------------------------------------------+
717| determine_pci_clock_per.
718+-------------------------------------------------------------------------*/
719unsigned long determine_pci_clock_per(void)
720{
721 unsigned long pci_clock_selection, pci_period;
722
723 /*-------------------------------------------------------------------------+
724 | Read FPGA reg 6 to get PCI 0 FPGA reg information
725 +-------------------------------------------------------------------------*/
726 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
727
728
729 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
730
731 switch (pci_clock_selection) {
732 case FPGA_REG16_PCI0_CLK_133_33:
733 pci_period = PERIOD_133_33MHZ;
734 break;
735 case FPGA_REG16_PCI0_CLK_100:
736 pci_period = PERIOD_100_00MHZ;
737 break;
738 case FPGA_REG16_PCI0_CLK_66_66:
739 pci_period = PERIOD_66_66MHZ;
740 break;
741 default:
742 pci_period = PERIOD_33_33MHZ;;
743 break;
744 }
745
746 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000747}
748#endif
wdenkc6097192002-11-03 00:24:07 +0000749
750ulong get_OPB_freq (void)
751{
752
753 sys_info_t sys_info;
754 get_sys_info (&sys_info);
755 return sys_info.freqOPB;
756}
757
Michal Simek9fea65a2008-06-24 09:54:09 +0200758#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000759extern void get_sys_info (sys_info_t * sysInfo);
760extern ulong get_PCI_freq (void);
761
Wolfgang Denk7521af12005-10-09 01:04:33 +0200762#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200763void get_sys_info (sys_info_t * sysInfo)
764{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200765 sysInfo->freqProcessor = 240 * 1000 * 1000;
766 sysInfo->freqPLB = 80 * 1000 * 1000;
767 sysInfo->freqPCI = 33 * 1000 * 1000;
768}
769
wdenkc6097192002-11-03 00:24:07 +0000770#elif defined(CONFIG_405)
771
Stefan Roesefa8aea22007-10-22 07:33:52 +0200772void get_sys_info (sys_info_t * sysInfo)
773{
wdenkc6097192002-11-03 00:24:07 +0000774 sysInfo->freqVCOMhz=3125000;
775 sysInfo->freqProcessor=12*1000*1000;
776 sysInfo->freqPLB=50*1000*1000;
777 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000778}
779
stroeseb867d702003-05-23 11:18:02 +0000780#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200781void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000782{
783 unsigned long pllmr0;
784 unsigned long pllmr1;
785 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
786 unsigned long m;
787 unsigned long pllmr0_ccdv;
788
789 /*
790 * Read PLL Mode registers
791 */
792 pllmr0 = mfdcr (cpc0_pllmr0);
793 pllmr1 = mfdcr (cpc0_pllmr1);
794
795 /*
796 * Determine forward divider A
797 */
798 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
799
800 /*
801 * Determine forward divider B (should be equal to A)
802 */
803 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
804
805 /*
806 * Determine FBK_DIV.
807 */
808 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200809 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000810 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000811
812 /*
813 * Determine PLB_DIV.
814 */
815 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
816
817 /*
818 * Determine PCI_DIV.
819 */
820 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
821
822 /*
823 * Determine EXTBUS_DIV.
824 */
825 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
826
827 /*
828 * Determine OPB_DIV.
829 */
830 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
831
832 /*
833 * Determine the M factor
834 */
835 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
836
837 /*
838 * Determine VCO clock frequency
839 */
stroeseb39392a2004-12-16 18:13:53 +0000840 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
841 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000842
843 /*
844 * Determine CPU clock frequency
845 */
846 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
847 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000848 /*
849 * This is true if FWDVA == FWDVB:
850 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
851 * / pllmr0_ccdv;
852 */
853 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
854 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000855 } else {
856 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
857 }
858
859 /*
860 * Determine PLB clock frequency
861 */
862 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200863
864 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200865
866 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000867}
868
869
870/********************************************
871 * get_OPB_freq
872 * return OPB bus freq in Hz
873 *********************************************/
874ulong get_OPB_freq (void)
875{
876 ulong val = 0;
877
Stefan Roese087dfdb2007-10-21 08:12:41 +0200878 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000879
880 get_sys_info (&sys_info);
881 val = sys_info.freqPLB / sys_info.pllOpbDiv;
882
883 return val;
884}
885
886
887/********************************************
888 * get_PCI_freq
889 * return PCI bus freq in Hz
890 *********************************************/
891ulong get_PCI_freq (void)
892{
893 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200894 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000895
896 get_sys_info (&sys_info);
897 val = sys_info.freqPLB / sys_info.pllPciDiv;
898 return val;
899}
900
Stefan Roesee01bd212007-03-21 13:38:59 +0100901#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200902void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100903{
904 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200905 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100906 unsigned long cpr_primad;
907 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
908 unsigned long primad_cpudv;
909 unsigned long m;
910
911 /*
912 * Read PLL Mode registers
913 */
914 mfcpr(cprplld, cpr_plld);
Stefan Roese273db7e2007-08-13 09:05:33 +0200915 mfcpr(cprpllc, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100916
917 /*
918 * Determine forward divider A
919 */
920 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
921
922 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200923 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100924 */
925 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200926 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100927 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100928
929 /*
930 * Determine FBK_DIV.
931 */
932 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200933 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100934 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100935
936 /*
937 * Read CPR_PRIMAD register
938 */
939 mfcpr(cprprimad, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200940
Stefan Roesee01bd212007-03-21 13:38:59 +0100941 /*
942 * Determine PLB_DIV.
943 */
944 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200945 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100946 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100947
948 /*
949 * Determine EXTBUS_DIV.
950 */
951 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200952 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100953 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100954
955 /*
956 * Determine OPB_DIV.
957 */
958 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200959 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100960 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100961
962 /*
963 * Determine the M factor
964 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200965 if (cpr_pllc & PLLC_SRC_MASK)
966 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
967 else
968 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100969
970 /*
971 * Determine VCO clock frequency
972 */
973 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
974 (unsigned long long)sysClkPeriodPs;
975
976 /*
977 * Determine CPU clock frequency
978 */
979 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200980 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100981 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100982
Stefan Roese273db7e2007-08-13 09:05:33 +0200983 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
984 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100985
986 /*
987 * Determine PLB clock frequency
988 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200989 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
990 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200991
992 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
993 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200994
995 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roesee01bd212007-03-21 13:38:59 +0100996}
997
998/********************************************
999 * get_OPB_freq
1000 * return OPB bus freq in Hz
1001 *********************************************/
1002ulong get_OPB_freq (void)
1003{
1004 ulong val = 0;
1005
Stefan Roese087dfdb2007-10-21 08:12:41 +02001006 PPC4xx_SYS_INFO sys_info;
Stefan Roesee01bd212007-03-21 13:38:59 +01001007
1008 get_sys_info (&sys_info);
1009 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1010
1011 return val;
1012}
1013
Stefan Roesedbbd1252007-10-05 17:10:59 +02001014#elif defined(CONFIG_405EX)
1015
1016/*
1017 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1018 * We need the specs!!!!
1019 */
1020static unsigned char get_fbdv(unsigned char index)
1021{
1022 unsigned char ret = 0;
1023 /* This is table should be 256 bytes.
1024 * Only take first 52 values.
1025 */
1026 unsigned char fbdv_tb[] = {
1027 0x00, 0xff, 0x7f, 0xfd,
1028 0x7a, 0xf5, 0x6a, 0xd5,
1029 0x2a, 0xd4, 0x29, 0xd3,
1030 0x26, 0xcc, 0x19, 0xb3,
1031 0x67, 0xce, 0x1d, 0xbb,
1032 0x77, 0xee, 0x5d, 0xba,
1033 0x74, 0xe9, 0x52, 0xa5,
1034 0x4b, 0x96, 0x2c, 0xd8,
1035 0x31, 0xe3, 0x46, 0x8d,
1036 0x1b, 0xb7, 0x6f, 0xde,
1037 0x3d, 0xfb, 0x76, 0xed,
1038 0x5a, 0xb5, 0x6b, 0xd6,
1039 0x2d, 0xdb, 0x36, 0xec,
1040
1041 };
1042
1043 if ((index & 0x7f) == 0)
1044 return 1;
1045 while (ret < sizeof (fbdv_tb)) {
1046 if (fbdv_tb[ret] == index)
1047 break;
1048 ret++;
1049 }
1050 ret++;
1051
1052 return ret;
1053}
1054
1055#define PLL_FBK_PLL_LOCAL 0
1056#define PLL_FBK_CPU 1
1057#define PLL_FBK_PERCLK 5
1058
1059void get_sys_info (sys_info_t * sysInfo)
1060{
1061 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1062 unsigned long m = 1;
1063 unsigned int tmp;
1064 unsigned char fwdva[16] = {
1065 1, 2, 14, 9, 4, 11, 16, 13,
1066 12, 5, 6, 15, 10, 7, 8, 3,
1067 };
1068 unsigned char sel, cpudv0, plb2xDiv;
1069
1070 mfcpr(cpr0_plld, tmp);
1071
1072 /*
1073 * Determine forward divider A
1074 */
1075 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1076
1077 /*
1078 * Determine FBK_DIV.
1079 */
1080 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1081
1082 /*
1083 * Determine PLBDV0
1084 */
1085 sysInfo->pllPlbDiv = 2;
1086
1087 /*
1088 * Determine PERDV0
1089 */
1090 mfcpr(cpr0_perd, tmp);
1091 tmp = (tmp >> 24) & 0x03;
1092 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1093
1094 /*
1095 * Determine OPBDV0
1096 */
1097 mfcpr(cpr0_opbd, tmp);
1098 tmp = (tmp >> 24) & 0x03;
1099 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1100
1101 /* Determine PLB2XDV0 */
1102 mfcpr(cpr0_plbd, tmp);
1103 tmp = (tmp >> 16) & 0x07;
1104 plb2xDiv = (tmp == 0) ? 8 : tmp;
1105
1106 /* Determine CPUDV0 */
1107 mfcpr(cpr0_cpud, tmp);
1108 tmp = (tmp >> 24) & 0x07;
1109 cpudv0 = (tmp == 0) ? 8 : tmp;
1110
1111 /* Determine SEL(5:7) in CPR0_PLLC */
1112 mfcpr(cpr0_pllc, tmp);
1113 sel = (tmp >> 24) & 0x07;
1114
1115 /*
1116 * Determine the M factor
1117 * PLL local: M = FBDV
1118 * CPU clock: M = FBDV * FWDVA * CPUDV0
1119 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1120 *
1121 */
1122 switch (sel) {
1123 case PLL_FBK_CPU:
1124 m = sysInfo->pllFwdDiv * cpudv0;
1125 break;
1126 case PLL_FBK_PERCLK:
1127 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1128 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1129 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001130 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001131 break;
1132 default:
1133 printf("%s unknown m\n", __FUNCTION__);
1134 return;
1135
1136 }
1137 m *= sysInfo->pllFbkDiv;
1138
1139 /*
1140 * Determine VCO clock frequency
1141 */
1142 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1143 (unsigned long long)sysClkPeriodPs;
1144
1145 /*
1146 * Determine CPU clock frequency
1147 */
1148 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1149
1150 /*
1151 * Determine PLB clock frequency, ddr1x should be the same
1152 */
1153 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1154 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1155 sysInfo->freqDDR = sysInfo->freqPLB;
1156 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001157 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001158}
1159
1160/********************************************
1161 * get_OPB_freq
1162 * return OPB bus freq in Hz
1163 *********************************************/
1164ulong get_OPB_freq (void)
1165{
1166 ulong val = 0;
1167
Stefan Roese087dfdb2007-10-21 08:12:41 +02001168 PPC4xx_SYS_INFO sys_info;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001169
1170 get_sys_info (&sys_info);
1171 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1172
1173 return val;
1174}
1175
wdenkc6097192002-11-03 00:24:07 +00001176#endif
1177
1178int get_clocks (void)
1179{
Stefan Roesee01bd212007-03-21 13:38:59 +01001180#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1181 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001182 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1183 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001184 sys_info_t sys_info;
1185
1186 get_sys_info (&sys_info);
1187 gd->cpu_clk = sys_info.freqProcessor;
1188 gd->bus_clk = sys_info.freqPLB;
1189
1190#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1191
1192#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001193 gd->cpu_clk = 66000000;
1194 gd->bus_clk = 66000000;
1195#endif
1196 return (0);
1197}
1198
1199
1200/********************************************
1201 * get_bus_freq
1202 * return PLB bus freq in Hz
1203 *********************************************/
1204ulong get_bus_freq (ulong dummy)
1205{
1206 ulong val;
1207
Stefan Roesee01bd212007-03-21 13:38:59 +01001208#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1209 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001210 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1211 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001212 sys_info_t sys_info;
1213
1214 get_sys_info (&sys_info);
1215 val = sys_info.freqPLB;
1216
1217#elif defined(CONFIG_IOP480)
1218
1219 val = 66;
1220
1221#else
1222# error get_bus_freq() not implemented
1223#endif
1224
1225 return val;
1226}