blob: 09d6671d0d8a7ea0091e63a65b0a75e6e8148012 [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
Wolfgang Denk7521af12005-10-09 01:04:33 +0200815#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200816void get_sys_info (sys_info_t * sysInfo)
817{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200818 sysInfo->freqProcessor = 240 * 1000 * 1000;
819 sysInfo->freqPLB = 80 * 1000 * 1000;
820 sysInfo->freqPCI = 33 * 1000 * 1000;
821}
822
wdenkc6097192002-11-03 00:24:07 +0000823#elif defined(CONFIG_405)
824
Stefan Roesefa8aea22007-10-22 07:33:52 +0200825void get_sys_info (sys_info_t * sysInfo)
826{
wdenkc6097192002-11-03 00:24:07 +0000827 sysInfo->freqVCOMhz=3125000;
828 sysInfo->freqProcessor=12*1000*1000;
829 sysInfo->freqPLB=50*1000*1000;
830 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000831}
832
stroeseb867d702003-05-23 11:18:02 +0000833#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200834void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000835{
836 unsigned long pllmr0;
837 unsigned long pllmr1;
838 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
839 unsigned long m;
840 unsigned long pllmr0_ccdv;
841
842 /*
843 * Read PLL Mode registers
844 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200845 pllmr0 = mfdcr (CPC0_PLLMR0);
846 pllmr1 = mfdcr (CPC0_PLLMR1);
stroeseb867d702003-05-23 11:18:02 +0000847
848 /*
849 * Determine forward divider A
850 */
851 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
852
853 /*
854 * Determine forward divider B (should be equal to A)
855 */
856 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
857
858 /*
859 * Determine FBK_DIV.
860 */
861 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200862 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000863 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000864
865 /*
866 * Determine PLB_DIV.
867 */
868 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
869
870 /*
871 * Determine PCI_DIV.
872 */
873 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
874
875 /*
876 * Determine EXTBUS_DIV.
877 */
878 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
879
880 /*
881 * Determine OPB_DIV.
882 */
883 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
884
885 /*
886 * Determine the M factor
887 */
888 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
889
890 /*
891 * Determine VCO clock frequency
892 */
stroeseb39392a2004-12-16 18:13:53 +0000893 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
894 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000895
896 /*
897 * Determine CPU clock frequency
898 */
899 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
900 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000901 /*
902 * This is true if FWDVA == FWDVB:
903 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
904 * / pllmr0_ccdv;
905 */
906 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
907 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000908 } else {
909 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
910 }
911
912 /*
913 * Determine PLB clock frequency
914 */
915 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200916
917 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200918
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200919 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
920
Stefan Roesefa8aea22007-10-22 07:33:52 +0200921 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000922}
923
924
925/********************************************
stroeseb867d702003-05-23 11:18:02 +0000926 * get_PCI_freq
927 * return PCI bus freq in Hz
928 *********************************************/
929ulong get_PCI_freq (void)
930{
931 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200932 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000933
934 get_sys_info (&sys_info);
935 val = sys_info.freqPLB / sys_info.pllPciDiv;
936 return val;
937}
938
Stefan Roesee01bd212007-03-21 13:38:59 +0100939#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200940void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100941{
942 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200943 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100944 unsigned long cpr_primad;
945 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
946 unsigned long primad_cpudv;
947 unsigned long m;
Stefan Roese95a4a592009-09-11 17:07:55 +0200948 unsigned long plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100949
950 /*
951 * Read PLL Mode registers
952 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200953 mfcpr(CPR0_PLLD, cpr_plld);
954 mfcpr(CPR0_PLLC, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100955
956 /*
957 * Determine forward divider A
958 */
959 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
960
961 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200962 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100963 */
964 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200965 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100966 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100967
968 /*
969 * Determine FBK_DIV.
970 */
971 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200972 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100973 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100974
975 /*
976 * Read CPR_PRIMAD register
977 */
Stefan Roeseafabb492010-09-12 06:21:37 +0200978 mfcpr(CPR0_PRIMAD, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200979
Stefan Roesee01bd212007-03-21 13:38:59 +0100980 /*
981 * Determine PLB_DIV.
982 */
983 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200984 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100985 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100986
987 /*
988 * Determine EXTBUS_DIV.
989 */
990 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200991 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100992 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100993
994 /*
995 * Determine OPB_DIV.
996 */
997 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200998 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100999 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +01001000
1001 /*
1002 * Determine the M factor
1003 */
Stefan Roese273db7e2007-08-13 09:05:33 +02001004 if (cpr_pllc & PLLC_SRC_MASK)
1005 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
1006 else
1007 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +01001008
1009 /*
1010 * Determine VCO clock frequency
1011 */
1012 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1013 (unsigned long long)sysClkPeriodPs;
1014
1015 /*
1016 * Determine CPU clock frequency
1017 */
1018 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +02001019 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +01001020 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +01001021
Stefan Roese273db7e2007-08-13 09:05:33 +02001022 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
1023 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +01001024
1025 /*
1026 * Determine PLB clock frequency
1027 */
Stefan Roese273db7e2007-08-13 09:05:33 +02001028 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1029 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001030
Stefan Roesee67af442009-09-14 11:13:34 +02001031 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1032 sysInfo->pllOpbDiv;
1033
Stefan Roesedbbd1252007-10-05 17:10:59 +02001034 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1035 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001036
Stefan Roese95a4a592009-09-11 17:07:55 +02001037 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1038 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1039 sysInfo->pllFwdDivB);
1040 sysInfo->freqUART = plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +01001041}
1042
Stefan Roesedbbd1252007-10-05 17:10:59 +02001043#elif defined(CONFIG_405EX)
1044
1045/*
1046 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1047 * We need the specs!!!!
1048 */
1049static unsigned char get_fbdv(unsigned char index)
1050{
1051 unsigned char ret = 0;
1052 /* This is table should be 256 bytes.
1053 * Only take first 52 values.
1054 */
1055 unsigned char fbdv_tb[] = {
1056 0x00, 0xff, 0x7f, 0xfd,
1057 0x7a, 0xf5, 0x6a, 0xd5,
1058 0x2a, 0xd4, 0x29, 0xd3,
1059 0x26, 0xcc, 0x19, 0xb3,
1060 0x67, 0xce, 0x1d, 0xbb,
1061 0x77, 0xee, 0x5d, 0xba,
1062 0x74, 0xe9, 0x52, 0xa5,
1063 0x4b, 0x96, 0x2c, 0xd8,
1064 0x31, 0xe3, 0x46, 0x8d,
1065 0x1b, 0xb7, 0x6f, 0xde,
1066 0x3d, 0xfb, 0x76, 0xed,
1067 0x5a, 0xb5, 0x6b, 0xd6,
1068 0x2d, 0xdb, 0x36, 0xec,
1069
1070 };
1071
1072 if ((index & 0x7f) == 0)
1073 return 1;
1074 while (ret < sizeof (fbdv_tb)) {
1075 if (fbdv_tb[ret] == index)
1076 break;
1077 ret++;
1078 }
1079 ret++;
1080
1081 return ret;
1082}
1083
1084#define PLL_FBK_PLL_LOCAL 0
1085#define PLL_FBK_CPU 1
1086#define PLL_FBK_PERCLK 5
1087
1088void get_sys_info (sys_info_t * sysInfo)
1089{
1090 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1091 unsigned long m = 1;
1092 unsigned int tmp;
1093 unsigned char fwdva[16] = {
1094 1, 2, 14, 9, 4, 11, 16, 13,
1095 12, 5, 6, 15, 10, 7, 8, 3,
1096 };
1097 unsigned char sel, cpudv0, plb2xDiv;
1098
Stefan Roesed1c3b272009-09-09 16:25:29 +02001099 mfcpr(CPR0_PLLD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001100
1101 /*
1102 * Determine forward divider A
1103 */
1104 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1105
1106 /*
1107 * Determine FBK_DIV.
1108 */
1109 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1110
1111 /*
1112 * Determine PLBDV0
1113 */
1114 sysInfo->pllPlbDiv = 2;
1115
1116 /*
1117 * Determine PERDV0
1118 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001119 mfcpr(CPR0_PERD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001120 tmp = (tmp >> 24) & 0x03;
1121 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1122
1123 /*
1124 * Determine OPBDV0
1125 */
Niklaus Gigerddc922f2009-10-04 20:04:20 +02001126 mfcpr(CPR0_OPBD0, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001127 tmp = (tmp >> 24) & 0x03;
1128 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1129
1130 /* Determine PLB2XDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001131 mfcpr(CPR0_PLBD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001132 tmp = (tmp >> 16) & 0x07;
1133 plb2xDiv = (tmp == 0) ? 8 : tmp;
1134
1135 /* Determine CPUDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001136 mfcpr(CPR0_CPUD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001137 tmp = (tmp >> 24) & 0x07;
1138 cpudv0 = (tmp == 0) ? 8 : tmp;
1139
1140 /* Determine SEL(5:7) in CPR0_PLLC */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001141 mfcpr(CPR0_PLLC, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001142 sel = (tmp >> 24) & 0x07;
1143
1144 /*
1145 * Determine the M factor
1146 * PLL local: M = FBDV
1147 * CPU clock: M = FBDV * FWDVA * CPUDV0
1148 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1149 *
1150 */
1151 switch (sel) {
1152 case PLL_FBK_CPU:
1153 m = sysInfo->pllFwdDiv * cpudv0;
1154 break;
1155 case PLL_FBK_PERCLK:
1156 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1157 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1158 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001159 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001160 break;
1161 default:
1162 printf("%s unknown m\n", __FUNCTION__);
1163 return;
1164
1165 }
1166 m *= sysInfo->pllFbkDiv;
1167
1168 /*
1169 * Determine VCO clock frequency
1170 */
1171 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1172 (unsigned long long)sysClkPeriodPs;
1173
1174 /*
1175 * Determine CPU clock frequency
1176 */
1177 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1178
1179 /*
1180 * Determine PLB clock frequency, ddr1x should be the same
1181 */
1182 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1183 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1184 sysInfo->freqDDR = sysInfo->freqPLB;
1185 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001186 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001187}
1188
wdenkc6097192002-11-03 00:24:07 +00001189#endif
1190
1191int get_clocks (void)
1192{
Stefan Roesee01bd212007-03-21 13:38:59 +01001193#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1194 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001195 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1196 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001197 sys_info_t sys_info;
1198
1199 get_sys_info (&sys_info);
1200 gd->cpu_clk = sys_info.freqProcessor;
1201 gd->bus_clk = sys_info.freqPLB;
1202
1203#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1204
1205#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001206 gd->cpu_clk = 66000000;
1207 gd->bus_clk = 66000000;
1208#endif
1209 return (0);
1210}
1211
1212
1213/********************************************
1214 * get_bus_freq
1215 * return PLB bus freq in Hz
1216 *********************************************/
1217ulong get_bus_freq (ulong dummy)
1218{
1219 ulong val;
1220
Stefan Roesee01bd212007-03-21 13:38:59 +01001221#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1222 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001223 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1224 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001225 sys_info_t sys_info;
1226
1227 get_sys_info (&sys_info);
1228 val = sys_info.freqPLB;
1229
1230#elif defined(CONFIG_IOP480)
1231
1232 val = 66;
1233
1234#else
1235# error get_bus_freq() not implemented
1236#endif
1237
1238 return val;
1239}
Stefan Roesee67af442009-09-14 11:13:34 +02001240
1241#if !defined(CONFIG_IOP480)
1242ulong get_OPB_freq (void)
1243{
1244 PPC4xx_SYS_INFO sys_info;
1245
1246 get_sys_info (&sys_info);
1247
1248 return sys_info.freqOPB;
1249}
1250#endif