blob: 45ef035b03ed34edf6f84ca12ee637430e8d83c8 [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>
Stefan Roeseb36df562010-09-09 19:18:00 +020026#include <asm/ppc4xx.h>
wdenkc6097192002-11-03 00:24:07 +000027#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 */
Stefan Roesed1c3b272009-09-09 16:25:29 +020053 pllmr = mfdcr (CPC0_PLLMR);
wdenkc6097192002-11-03 00:24:07 +000054
55 /*
56 * Read Pin Strapping register
57 */
Stefan Roesed1c3b272009-09-09 16:25:29 +020058 psr = mfdcr (CPC0_PSR);
wdenkc6097192002-11-03 00:24:07 +000059
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
Stefan Roesee67af442009-09-14 11:13:34 +0200168 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
Matthias Fuchse1d09682008-04-18 17:24:32 +0200169 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200170 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000171}
172
173
174/********************************************
wdenkc6097192002-11-03 00:24:07 +0000175 * get_PCI_freq
176 * return PCI bus freq in Hz
177 *********************************************/
178ulong get_PCI_freq (void)
179{
180 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200181 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000182
183 get_sys_info (&sys_info);
184 val = sys_info.freqPLB / sys_info.pllPciDiv;
185 return val;
186}
187
188
189#elif defined(CONFIG_440)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200190
Feng Kan7d307932008-07-08 22:47:31 -0700191#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
Tirumala Marri1b8fec12010-09-28 14:15:14 -0700192 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
Stefan Roese2801b2d2008-03-11 15:05:50 +0100193static u8 pll_fwdv_multi_bits[] = {
194 /* values for: 1 - 16 */
195 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
196 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
197};
198
199u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
200{
201 u32 index;
202
203 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
204 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
205 return index + 1;
206
207 return 0;
208}
209
210static u8 pll_fbdv_multi_bits[] = {
211 /* values for: 1 - 100 */
212 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
213 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
214 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
215 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
216 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
217 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
218 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
219 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
220 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
221 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
222 /* values for: 101 - 200 */
223 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
224 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchellb9bbefc2008-05-07 09:00:23 -0700225 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roese2801b2d2008-03-11 15:05:50 +0100226 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
227 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
228 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
229 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
230 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
231 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
232 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
233 /* values for: 201 - 255 */
234 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
235 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
236 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
237 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
238 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
239 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
240};
241
242u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
243{
244 u32 index;
245
246 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
247 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
248 return index + 1;
249
250 return 0;
251}
252
Tirumala Marri1b8fec12010-09-28 14:15:14 -0700253#if defined(CONFIG_APM821XX)
254
255void get_sys_info(sys_info_t *sysInfo)
256{
257 unsigned long plld;
258 unsigned long temp;
259 unsigned long mul;
260 unsigned long cpudv;
261 unsigned long plb2dv;
262 unsigned long ddr2dv;
263
264 /* Calculate Forward divisor A and Feeback divisor */
265 mfcpr(CPR0_PLLD, plld);
266
267 temp = CPR0_PLLD_FWDVA(plld);
268 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
269
270 temp = CPR0_PLLD_FDV(plld);
271 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
272
273 /* Calculate OPB clock divisor */
274 mfcpr(CPR0_OPBD, temp);
275 temp = CPR0_OPBD_OPBDV(temp);
276 sysInfo->pllOpbDiv = temp ? temp : 4;
277
278 /* Calculate Peripheral clock divisor */
279 mfcpr(CPR0_PERD, temp);
280 temp = CPR0_PERD_PERDV(temp);
281 sysInfo->pllExtBusDiv = temp ? temp : 4;
282
283 /* Calculate CPU clock divisor */
284 mfcpr(CPR0_CPUD, temp);
285 temp = CPR0_CPUD_CPUDV(temp);
286 cpudv = temp ? temp : 8;
287
288 /* Calculate PLB2 clock divisor */
289 mfcpr(CPR0_PLB2D, temp);
290 temp = CPR0_PLB2D_PLB2DV(temp);
291 plb2dv = temp ? temp : 4;
292
293 /* Calculate DDR2 clock divisor */
294 mfcpr(CPR0_DDR2D, temp);
295 temp = CPR0_DDR2D_DDR2DV(temp);
296 ddr2dv = temp ? temp : 4;
297
298 /* Calculate 'M' based on feedback source */
299 mfcpr(CPR0_PLLC, temp);
300 temp = CPR0_PLLC_SEL(temp);
301 if (temp == 0) {
302 /* PLL internal feedback */
303 mul = sysInfo->pllFbkDiv;
304 } else {
305 /* PLL PerClk feedback */
306 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
307 * plb2dv * 2 * sysInfo->pllOpbDiv *
308 sysInfo->pllExtBusDiv;
309 }
310
311 /* Now calculate the individual clocks */
312 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
313 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
314 sysInfo->pllFwdDivA / cpudv;
315 sysInfo->freqPLB = sysInfo->freqVCOMhz /
316 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
317 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
318 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
319 sysInfo->freqDDR = sysInfo->freqVCOMhz /
320 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
321 sysInfo->freqUART = sysInfo->freqPLB;
322}
323
324#else
Stefan Roese2801b2d2008-03-11 15:05:50 +0100325/*
326 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
327 * with latest EAS
328 */
329void get_sys_info (sys_info_t * sysInfo)
330{
331 unsigned long strp0;
332 unsigned long strp1;
333 unsigned long temp;
334 unsigned long m;
335 unsigned long plbedv0;
336
337 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200338 mfsdr(SDR0_SDSTP0, strp0);
339 mfsdr(SDR0_SDSTP1, strp1);
Stefan Roese2801b2d2008-03-11 15:05:50 +0100340
341 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
342 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
343
344 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
345 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
346
347 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
348 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
349
350 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
351 sysInfo->pllOpbDiv = temp ? temp : 4;
352
353 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
354 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
355 sysInfo->pllExtBusDiv = temp ? temp : 4;
356
357 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
358 plbedv0 = temp ? temp: 8;
359
360 /* Calculate 'M' based on feedback source */
361 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
362 if (temp == 0) {
363 /* PLL internal feedback */
364 m = sysInfo->pllFbkDiv;
365 } else {
366 /* PLL PerClk feedback */
367 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
368 sysInfo->pllExtBusDiv;
369 }
370
371 /* Now calculate the individual clocks */
372 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
373 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
374 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
375 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
376 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
377 sysInfo->freqDDR = sysInfo->freqPLB;
378 sysInfo->freqUART = sysInfo->freqPLB;
379
380 return;
381}
Tirumala Marri1b8fec12010-09-28 14:15:14 -0700382#endif
Stefan Roese2801b2d2008-03-11 15:05:50 +0100383
384#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200385 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200386void get_sys_info (sys_info_t *sysInfo)
387{
388 unsigned long temp;
389 unsigned long reg;
390 unsigned long lfdiv;
391 unsigned long m;
392 unsigned long prbdv0;
393 /*
394 WARNING: ASSUMES the following:
395 ENG=1
396 PRADV0=1
397 PRBDV0=1
398 */
399
400 /* Decode CPR0_PLLD0 for divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200401 mfcpr(CPR0_PLLD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200402 temp = (reg & PLLD_FWDVA_MASK) >> 16;
403 sysInfo->pllFwdDivA = temp ? temp : 16;
404 temp = (reg & PLLD_FWDVB_MASK) >> 8;
405 sysInfo->pllFwdDivB = temp ? temp: 8 ;
406 temp = (reg & PLLD_FBDV_MASK) >> 24;
407 sysInfo->pllFbkDiv = temp ? temp : 32;
408 lfdiv = reg & PLLD_LFBDV_MASK;
409
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200410 mfcpr(CPR0_OPBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200411 temp = (reg & OPBDDV_MASK) >> 24;
412 sysInfo->pllOpbDiv = temp ? temp : 4;
413
Stefan Roesed1c3b272009-09-09 16:25:29 +0200414 mfcpr(CPR0_PERD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200415 temp = (reg & PERDV_MASK) >> 24;
416 sysInfo->pllExtBusDiv = temp ? temp : 8;
417
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200418 mfcpr(CPR0_PRIMBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200419 temp = (reg & PRBDV_MASK) >> 24;
420 prbdv0 = temp ? temp : 8;
421
Stefan Roesed1c3b272009-09-09 16:25:29 +0200422 mfcpr(CPR0_SPCID, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200423 temp = (reg & SPCID_MASK) >> 24;
424 sysInfo->pllPciDiv = temp ? temp : 4;
425
426 /* Calculate 'M' based on feedback source */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200427 mfsdr(SDR0_SDSTP0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200428 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
429 if (temp == 0) { /* PLL output */
430 /* Figure which pll to use */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200431 mfcpr(CPR0_PLLC, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200432 temp = (reg & PLLC_SRC_MASK) >> 29;
433 if (!temp) /* PLLOUTA */
434 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
435 else /* PLLOUTB */
436 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
437 }
438 else if (temp == 1) /* CPU output */
439 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
440 else /* PerClk */
441 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
442
443 /* Now calculate the individual clocks */
444 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
445 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
446 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
447 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200448 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200449 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200450 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200451
452 /* Figure which timer source to use */
Matthias Fuchs58ea1422009-07-22 17:27:56 +0200453 if (mfspr(SPRN_CCR1) & 0x0080) {
454 /* External Clock, assume same as SYS_CLK */
Stefan Roesec157d8e2005-08-01 16:41:48 +0200455 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
456 if (CONFIG_SYS_CLK_FREQ > temp)
457 sysInfo->freqTmrClk = temp;
458 else
459 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
460 }
461 else /* Internal clock */
462 sysInfo->freqTmrClk = sysInfo->freqProcessor;
463}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200464
Stefan Roesec157d8e2005-08-01 16:41:48 +0200465/********************************************
466 * get_PCI_freq
467 * return PCI bus freq in Hz
468 *********************************************/
469ulong get_PCI_freq (void)
470{
471 sys_info_t sys_info;
472 get_sys_info (&sys_info);
473 return sys_info.freqPCI;
474}
475
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200476#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
477 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000478void get_sys_info (sys_info_t * sysInfo)
479{
480 unsigned long strp0;
481 unsigned long temp;
482 unsigned long m;
483
484 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200485 strp0 = mfdcr( CPC0_STRP0 );
wdenkc6097192002-11-03 00:24:07 +0000486 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
487 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
488 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
489 sysInfo->pllFbkDiv = temp ? temp : 16;
490 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
491 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
492
493 /* Calculate 'M' based on feedback source */
494 if( strp0 & PLLSYS0_EXTSL_MASK )
495 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
496 else
497 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
498
499 /* Now calculate the individual clocks */
500 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
501 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
502 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200503 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
504 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000505 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200506 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200507 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000508}
wdenkba56f622004-02-06 23:19:44 +0000509#else
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200510
511#if !defined(CONFIG_XILINX_440)
wdenkba56f622004-02-06 23:19:44 +0000512void get_sys_info (sys_info_t * sysInfo)
513{
514 unsigned long strp0;
515 unsigned long strp1;
516 unsigned long temp;
517 unsigned long temp1;
518 unsigned long lfdiv;
519 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000520 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000521
Stefan Roese4745aca2007-02-20 10:57:08 +0100522#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200523 unsigned long sys_freq;
524 unsigned long sys_per=0;
525 unsigned long msr;
526 unsigned long pci_clock_per;
527 unsigned long sdr_ddrpll;
528
529 /*-------------------------------------------------------------------------+
530 | Get the system clock period.
531 +-------------------------------------------------------------------------*/
532 sys_per = determine_sysper();
533
534 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
535
536 /*-------------------------------------------------------------------------+
537 | Calculate the system clock speed from the period.
538 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100539 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200540#endif
541
wdenkba56f622004-02-06 23:19:44 +0000542 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200543 mfsdr( SDR0_SDSTP0,strp0 );
544 mfsdr( SDR0_SDSTP1,strp1 );
wdenkba56f622004-02-06 23:19:44 +0000545
546 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
547 sysInfo->pllFwdDivA = temp ? temp : 16 ;
548 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
549 sysInfo->pllFwdDivB = temp ? temp: 8 ;
550 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
551 sysInfo->pllFbkDiv = temp ? temp : 32;
552 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
553 sysInfo->pllOpbDiv = temp ? temp : 4;
554 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
555 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000556 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000557
558 /* Calculate 'M' based on feedback source */
559 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
560 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
561 lfdiv = temp1 ? temp1 : 64;
562 if (temp == 0) { /* PLL output */
563 /* Figure which pll to use */
564 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
565 if (!temp)
566 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
567 else
568 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
569 }
570 else if (temp == 1) /* CPU output */
571 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
572 else /* PerClk */
573 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
574
575 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100576#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200577 sysInfo->freqVCOMhz = (m * sys_freq) ;
578#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100579 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200580#endif
wdenkba56f622004-02-06 23:19:44 +0000581 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000582 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000583 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200584 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000585
Stefan Roese4745aca2007-02-20 10:57:08 +0100586#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200587 /* Determine PCI Clock Period */
588 pci_clock_per = determine_pci_clock_per();
589 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
Stefan Roesed1c3b272009-09-09 16:25:29 +0200590 mfsdr(SDR0_DDR0, sdr_ddrpll);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200591 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
592#endif
593
Stefan Roesefa8aea22007-10-22 07:33:52 +0200594 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200595}
596
597#endif
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200598#endif /* CONFIG_XILINX_440 */
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200599
Stefan Roese4745aca2007-02-20 10:57:08 +0100600#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200601unsigned long determine_sysper(void)
602{
603 unsigned int fpga_clocking_reg;
604 unsigned int master_clock_selection;
605 unsigned long master_clock_per = 0;
606 unsigned long fb_div_selection;
607 unsigned int vco_div_reg_value;
608 unsigned long vco_div_selection;
609 unsigned long sys_per = 0;
610 int extClkVal;
611
612 /*-------------------------------------------------------------------------+
613 | Read FPGA reg 0 and reg 1 to get FPGA reg information
614 +-------------------------------------------------------------------------*/
615 fpga_clocking_reg = in16(FPGA_REG16);
616
617
618 /* Determine Master Clock Source Selection */
619 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
620
621 switch(master_clock_selection) {
622 case FPGA_REG16_MASTER_CLK_66_66:
623 master_clock_per = PERIOD_66_66MHZ;
624 break;
625 case FPGA_REG16_MASTER_CLK_50:
626 master_clock_per = PERIOD_50_00MHZ;
627 break;
628 case FPGA_REG16_MASTER_CLK_33_33:
629 master_clock_per = PERIOD_33_33MHZ;
630 break;
631 case FPGA_REG16_MASTER_CLK_25:
632 master_clock_per = PERIOD_25_00MHZ;
633 break;
634 case FPGA_REG16_MASTER_CLK_EXT:
635 if ((extClkVal==EXTCLK_33_33)
636 && (extClkVal==EXTCLK_50)
637 && (extClkVal==EXTCLK_66_66)
638 && (extClkVal==EXTCLK_83)) {
639 /* calculate master clock period from external clock value */
640 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
641 } else {
642 /* Unsupported */
643 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
644 hang();
645 }
646 break;
647 default:
648 /* Unsupported */
649 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
650 hang();
651 break;
652 }
653
654 /* Determine FB divisors values */
655 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
656 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
657 fb_div_selection = FPGA_FB_DIV_6;
658 else
659 fb_div_selection = FPGA_FB_DIV_12;
660 } else {
661 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
662 fb_div_selection = FPGA_FB_DIV_10;
663 else
664 fb_div_selection = FPGA_FB_DIV_20;
665 }
666
667 /* Determine VCO divisors values */
668 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
669
670 switch(vco_div_reg_value) {
671 case FPGA_REG16_VCO_DIV_4:
672 vco_div_selection = FPGA_VCO_DIV_4;
673 break;
674 case FPGA_REG16_VCO_DIV_6:
675 vco_div_selection = FPGA_VCO_DIV_6;
676 break;
677 case FPGA_REG16_VCO_DIV_8:
678 vco_div_selection = FPGA_VCO_DIV_8;
679 break;
680 case FPGA_REG16_VCO_DIV_10:
681 default:
682 vco_div_selection = FPGA_VCO_DIV_10;
683 break;
684 }
685
686 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
687 switch(master_clock_per) {
688 case PERIOD_25_00MHZ:
689 if (fb_div_selection == FPGA_FB_DIV_12) {
690 if (vco_div_selection == FPGA_VCO_DIV_4)
691 sys_per = PERIOD_75_00MHZ;
692 if (vco_div_selection == FPGA_VCO_DIV_6)
693 sys_per = PERIOD_50_00MHZ;
694 }
695 break;
696 case PERIOD_33_33MHZ:
697 if (fb_div_selection == FPGA_FB_DIV_6) {
698 if (vco_div_selection == FPGA_VCO_DIV_4)
699 sys_per = PERIOD_50_00MHZ;
700 if (vco_div_selection == FPGA_VCO_DIV_6)
701 sys_per = PERIOD_33_33MHZ;
702 }
703 if (fb_div_selection == FPGA_FB_DIV_10) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_83_33MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_10)
707 sys_per = PERIOD_33_33MHZ;
708 }
709 if (fb_div_selection == FPGA_FB_DIV_12) {
710 if (vco_div_selection == FPGA_VCO_DIV_4)
711 sys_per = PERIOD_100_00MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_6)
713 sys_per = PERIOD_66_66MHZ;
714 if (vco_div_selection == FPGA_VCO_DIV_8)
715 sys_per = PERIOD_50_00MHZ;
716 }
717 break;
718 case PERIOD_50_00MHZ:
719 if (fb_div_selection == FPGA_FB_DIV_6) {
720 if (vco_div_selection == FPGA_VCO_DIV_4)
721 sys_per = PERIOD_75_00MHZ;
722 if (vco_div_selection == FPGA_VCO_DIV_6)
723 sys_per = PERIOD_50_00MHZ;
724 }
725 if (fb_div_selection == FPGA_FB_DIV_10) {
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_83_33MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_10)
729 sys_per = PERIOD_50_00MHZ;
730 }
731 if (fb_div_selection == FPGA_FB_DIV_12) {
732 if (vco_div_selection == FPGA_VCO_DIV_6)
733 sys_per = PERIOD_100_00MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_8)
735 sys_per = PERIOD_75_00MHZ;
736 }
737 break;
738 case PERIOD_66_66MHZ:
739 if (fb_div_selection == FPGA_FB_DIV_6) {
740 if (vco_div_selection == FPGA_VCO_DIV_4)
741 sys_per = PERIOD_100_00MHZ;
742 if (vco_div_selection == FPGA_VCO_DIV_6)
743 sys_per = PERIOD_66_66MHZ;
744 if (vco_div_selection == FPGA_VCO_DIV_8)
745 sys_per = PERIOD_50_00MHZ;
746 }
747 if (fb_div_selection == FPGA_FB_DIV_10) {
748 if (vco_div_selection == FPGA_VCO_DIV_8)
749 sys_per = PERIOD_83_33MHZ;
750 if (vco_div_selection == FPGA_VCO_DIV_10)
751 sys_per = PERIOD_66_66MHZ;
752 }
753 if (fb_div_selection == FPGA_FB_DIV_12) {
754 if (vco_div_selection == FPGA_VCO_DIV_8)
755 sys_per = PERIOD_100_00MHZ;
756 }
757 break;
758 default:
759 break;
760 }
761
762 if (sys_per == 0) {
763 /* Other combinations are not supported */
764 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
765 hang();
766 }
767 } else {
768 /* calcul system clock without cheking */
769 /* if engineering option clock no check is selected */
770 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
771 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
772 }
773
774 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200775}
776
777/*-------------------------------------------------------------------------+
778| determine_pci_clock_per.
779+-------------------------------------------------------------------------*/
780unsigned long determine_pci_clock_per(void)
781{
782 unsigned long pci_clock_selection, pci_period;
783
784 /*-------------------------------------------------------------------------+
785 | Read FPGA reg 6 to get PCI 0 FPGA reg information
786 +-------------------------------------------------------------------------*/
787 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
788
789
790 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
791
792 switch (pci_clock_selection) {
793 case FPGA_REG16_PCI0_CLK_133_33:
794 pci_period = PERIOD_133_33MHZ;
795 break;
796 case FPGA_REG16_PCI0_CLK_100:
797 pci_period = PERIOD_100_00MHZ;
798 break;
799 case FPGA_REG16_PCI0_CLK_66_66:
800 pci_period = PERIOD_66_66MHZ;
801 break;
802 default:
803 pci_period = PERIOD_33_33MHZ;;
804 break;
805 }
806
807 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000808}
809#endif
wdenkc6097192002-11-03 00:24:07 +0000810
Michal Simek9fea65a2008-06-24 09:54:09 +0200811#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000812extern void get_sys_info (sys_info_t * sysInfo);
813extern ulong get_PCI_freq (void);
814
wdenkc6097192002-11-03 00:24:07 +0000815#elif defined(CONFIG_405)
816
Stefan Roesefa8aea22007-10-22 07:33:52 +0200817void get_sys_info (sys_info_t * sysInfo)
818{
wdenkc6097192002-11-03 00:24:07 +0000819 sysInfo->freqVCOMhz=3125000;
820 sysInfo->freqProcessor=12*1000*1000;
821 sysInfo->freqPLB=50*1000*1000;
822 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000823}
824
stroeseb867d702003-05-23 11:18:02 +0000825#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200826void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000827{
828 unsigned long pllmr0;
829 unsigned long pllmr1;
830 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
831 unsigned long m;
832 unsigned long pllmr0_ccdv;
833
834 /*
835 * Read PLL Mode registers
836 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200837 pllmr0 = mfdcr (CPC0_PLLMR0);
838 pllmr1 = mfdcr (CPC0_PLLMR1);
stroeseb867d702003-05-23 11:18:02 +0000839
840 /*
841 * Determine forward divider A
842 */
843 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
844
845 /*
846 * Determine forward divider B (should be equal to A)
847 */
848 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
849
850 /*
851 * Determine FBK_DIV.
852 */
853 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200854 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000855 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000856
857 /*
858 * Determine PLB_DIV.
859 */
860 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
861
862 /*
863 * Determine PCI_DIV.
864 */
865 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
866
867 /*
868 * Determine EXTBUS_DIV.
869 */
870 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
871
872 /*
873 * Determine OPB_DIV.
874 */
875 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
876
877 /*
878 * Determine the M factor
879 */
880 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
881
882 /*
883 * Determine VCO clock frequency
884 */
stroeseb39392a2004-12-16 18:13:53 +0000885 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
886 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000887
888 /*
889 * Determine CPU clock frequency
890 */
891 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
892 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000893 /*
894 * This is true if FWDVA == FWDVB:
895 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
896 * / pllmr0_ccdv;
897 */
898 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
899 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000900 } else {
901 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
902 }
903
904 /*
905 * Determine PLB clock frequency
906 */
907 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200908
909 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200910
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200911 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
912
Stefan Roesefa8aea22007-10-22 07:33:52 +0200913 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000914}
915
916
917/********************************************
stroeseb867d702003-05-23 11:18:02 +0000918 * get_PCI_freq
919 * return PCI bus freq in Hz
920 *********************************************/
921ulong get_PCI_freq (void)
922{
923 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200924 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000925
926 get_sys_info (&sys_info);
927 val = sys_info.freqPLB / sys_info.pllPciDiv;
928 return val;
929}
930
Stefan Roesee01bd212007-03-21 13:38:59 +0100931#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200932void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100933{
934 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200935 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100936 unsigned long cpr_primad;
937 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
938 unsigned long primad_cpudv;
939 unsigned long m;
Stefan Roese95a4a592009-09-11 17:07:55 +0200940 unsigned long plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100941
942 /*
943 * Read PLL Mode registers
944 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200945 mfcpr(CPR0_PLLD, cpr_plld);
946 mfcpr(CPR0_PLLC, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100947
948 /*
949 * Determine forward divider A
950 */
951 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
952
953 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200954 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100955 */
956 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200957 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100958 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100959
960 /*
961 * Determine FBK_DIV.
962 */
963 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200964 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100965 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100966
967 /*
968 * Read CPR_PRIMAD register
969 */
Stefan Roeseafabb492010-09-12 06:21:37 +0200970 mfcpr(CPR0_PRIMAD, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200971
Stefan Roesee01bd212007-03-21 13:38:59 +0100972 /*
973 * Determine PLB_DIV.
974 */
975 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200976 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100977 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100978
979 /*
980 * Determine EXTBUS_DIV.
981 */
982 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200983 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100984 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100985
986 /*
987 * Determine OPB_DIV.
988 */
989 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200990 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100991 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100992
993 /*
994 * Determine the M factor
995 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200996 if (cpr_pllc & PLLC_SRC_MASK)
997 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
998 else
999 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +01001000
1001 /*
1002 * Determine VCO clock frequency
1003 */
1004 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1005 (unsigned long long)sysClkPeriodPs;
1006
1007 /*
1008 * Determine CPU clock frequency
1009 */
1010 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +02001011 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +01001012 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +01001013
Stefan Roese273db7e2007-08-13 09:05:33 +02001014 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1015 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +01001016
1017 /*
1018 * Determine PLB clock frequency
1019 */
Stefan Roese273db7e2007-08-13 09:05:33 +02001020 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1021 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001022
Stefan Roesee67af442009-09-14 11:13:34 +02001023 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1024 sysInfo->pllOpbDiv;
1025
Stefan Roesedbbd1252007-10-05 17:10:59 +02001026 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1027 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001028
Stefan Roese95a4a592009-09-11 17:07:55 +02001029 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1030 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1031 sysInfo->pllFwdDivB);
1032 sysInfo->freqUART = plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +01001033}
1034
Stefan Roesedbbd1252007-10-05 17:10:59 +02001035#elif defined(CONFIG_405EX)
1036
1037/*
1038 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1039 * We need the specs!!!!
1040 */
1041static unsigned char get_fbdv(unsigned char index)
1042{
1043 unsigned char ret = 0;
1044 /* This is table should be 256 bytes.
1045 * Only take first 52 values.
1046 */
1047 unsigned char fbdv_tb[] = {
1048 0x00, 0xff, 0x7f, 0xfd,
1049 0x7a, 0xf5, 0x6a, 0xd5,
1050 0x2a, 0xd4, 0x29, 0xd3,
1051 0x26, 0xcc, 0x19, 0xb3,
1052 0x67, 0xce, 0x1d, 0xbb,
1053 0x77, 0xee, 0x5d, 0xba,
1054 0x74, 0xe9, 0x52, 0xa5,
1055 0x4b, 0x96, 0x2c, 0xd8,
1056 0x31, 0xe3, 0x46, 0x8d,
1057 0x1b, 0xb7, 0x6f, 0xde,
1058 0x3d, 0xfb, 0x76, 0xed,
1059 0x5a, 0xb5, 0x6b, 0xd6,
1060 0x2d, 0xdb, 0x36, 0xec,
1061
1062 };
1063
1064 if ((index & 0x7f) == 0)
1065 return 1;
1066 while (ret < sizeof (fbdv_tb)) {
1067 if (fbdv_tb[ret] == index)
1068 break;
1069 ret++;
1070 }
1071 ret++;
1072
1073 return ret;
1074}
1075
1076#define PLL_FBK_PLL_LOCAL 0
1077#define PLL_FBK_CPU 1
1078#define PLL_FBK_PERCLK 5
1079
1080void get_sys_info (sys_info_t * sysInfo)
1081{
1082 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1083 unsigned long m = 1;
1084 unsigned int tmp;
1085 unsigned char fwdva[16] = {
1086 1, 2, 14, 9, 4, 11, 16, 13,
1087 12, 5, 6, 15, 10, 7, 8, 3,
1088 };
1089 unsigned char sel, cpudv0, plb2xDiv;
1090
Stefan Roesed1c3b272009-09-09 16:25:29 +02001091 mfcpr(CPR0_PLLD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001092
1093 /*
1094 * Determine forward divider A
1095 */
1096 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1097
1098 /*
1099 * Determine FBK_DIV.
1100 */
1101 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1102
1103 /*
1104 * Determine PLBDV0
1105 */
1106 sysInfo->pllPlbDiv = 2;
1107
1108 /*
1109 * Determine PERDV0
1110 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001111 mfcpr(CPR0_PERD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001112 tmp = (tmp >> 24) & 0x03;
1113 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1114
1115 /*
1116 * Determine OPBDV0
1117 */
Niklaus Gigerddc922f2009-10-04 20:04:20 +02001118 mfcpr(CPR0_OPBD0, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001119 tmp = (tmp >> 24) & 0x03;
1120 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1121
1122 /* Determine PLB2XDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001123 mfcpr(CPR0_PLBD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001124 tmp = (tmp >> 16) & 0x07;
1125 plb2xDiv = (tmp == 0) ? 8 : tmp;
1126
1127 /* Determine CPUDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001128 mfcpr(CPR0_CPUD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001129 tmp = (tmp >> 24) & 0x07;
1130 cpudv0 = (tmp == 0) ? 8 : tmp;
1131
1132 /* Determine SEL(5:7) in CPR0_PLLC */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001133 mfcpr(CPR0_PLLC, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001134 sel = (tmp >> 24) & 0x07;
1135
1136 /*
1137 * Determine the M factor
1138 * PLL local: M = FBDV
1139 * CPU clock: M = FBDV * FWDVA * CPUDV0
1140 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1141 *
1142 */
1143 switch (sel) {
1144 case PLL_FBK_CPU:
1145 m = sysInfo->pllFwdDiv * cpudv0;
1146 break;
1147 case PLL_FBK_PERCLK:
1148 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1149 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1150 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001151 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001152 break;
1153 default:
1154 printf("%s unknown m\n", __FUNCTION__);
1155 return;
1156
1157 }
1158 m *= sysInfo->pllFbkDiv;
1159
1160 /*
1161 * Determine VCO clock frequency
1162 */
1163 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1164 (unsigned long long)sysClkPeriodPs;
1165
1166 /*
1167 * Determine CPU clock frequency
1168 */
1169 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1170
1171 /*
1172 * Determine PLB clock frequency, ddr1x should be the same
1173 */
1174 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1175 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1176 sysInfo->freqDDR = sysInfo->freqPLB;
1177 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001178 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001179}
1180
wdenkc6097192002-11-03 00:24:07 +00001181#endif
1182
1183int get_clocks (void)
1184{
wdenkc6097192002-11-03 00:24:07 +00001185 sys_info_t sys_info;
1186
1187 get_sys_info (&sys_info);
1188 gd->cpu_clk = sys_info.freqProcessor;
1189 gd->bus_clk = sys_info.freqPLB;
1190
wdenkc6097192002-11-03 00:24:07 +00001191 return (0);
1192}
1193
1194
1195/********************************************
1196 * get_bus_freq
1197 * return PLB bus freq in Hz
1198 *********************************************/
1199ulong get_bus_freq (ulong dummy)
1200{
1201 ulong val;
1202
Stefan Roesee01bd212007-03-21 13:38:59 +01001203#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1204 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001205 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1206 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001207 sys_info_t sys_info;
1208
1209 get_sys_info (&sys_info);
1210 val = sys_info.freqPLB;
wdenkc6097192002-11-03 00:24:07 +00001211#else
1212# error get_bus_freq() not implemented
1213#endif
1214
1215 return val;
1216}
Stefan Roesee67af442009-09-14 11:13:34 +02001217
Stefan Roesee67af442009-09-14 11:13:34 +02001218ulong get_OPB_freq (void)
1219{
1220 PPC4xx_SYS_INFO sys_info;
1221
1222 get_sys_info (&sys_info);
1223
1224 return sys_info.freqOPB;
1225}