blob: 906face033030fac18bad2a77b17daca13f39b70 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
Stefan Roese2801b2d2008-03-11 15:05:50 +01002 * (C) Copyright 2000-2008
wdenkc6097192002-11-03 00:24:07 +00003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <ppc_asm.tmpl>
26#include <ppc4xx.h>
27#include <asm/processor.h>
28
Wolfgang Denkd87080b2006-03-31 18:32:53 +020029DECLARE_GLOBAL_DATA_PTR;
wdenkc6097192002-11-03 00:24:07 +000030
31#define ONE_BILLION 1000000000
Marian Balakowicz6c5879f2006-06-30 16:30:46 +020032#ifdef DEBUG
33#define DEBUGF(fmt,args...) printf(fmt ,##args)
34#else
35#define DEBUGF(fmt,args...)
36#endif
wdenkc6097192002-11-03 00:24:07 +000037
Stefan Roese2801b2d2008-03-11 15:05:50 +010038#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
39
wdenkc6097192002-11-03 00:24:07 +000040#if defined(CONFIG_405GP) || defined(CONFIG_405CR)
41
Stefan Roese087dfdb2007-10-21 08:12:41 +020042void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
wdenkc6097192002-11-03 00:24:07 +000043{
44 unsigned long pllmr;
45 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
46 uint pvr = get_pvr();
47 unsigned long psr;
48 unsigned long m;
49
50 /*
51 * Read PLL Mode register
52 */
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) || \
192 defined(CONFIG_460SX)
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
253/*
254 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
255 * with latest EAS
256 */
257void get_sys_info (sys_info_t * sysInfo)
258{
259 unsigned long strp0;
260 unsigned long strp1;
261 unsigned long temp;
262 unsigned long m;
263 unsigned long plbedv0;
264
265 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200266 mfsdr(SDR0_SDSTP0, strp0);
267 mfsdr(SDR0_SDSTP1, strp1);
Stefan Roese2801b2d2008-03-11 15:05:50 +0100268
269 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
270 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
271
272 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
273 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
274
275 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
276 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
277
278 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
279 sysInfo->pllOpbDiv = temp ? temp : 4;
280
281 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
282 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
283 sysInfo->pllExtBusDiv = temp ? temp : 4;
284
285 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
286 plbedv0 = temp ? temp: 8;
287
288 /* Calculate 'M' based on feedback source */
289 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
290 if (temp == 0) {
291 /* PLL internal feedback */
292 m = sysInfo->pllFbkDiv;
293 } else {
294 /* PLL PerClk feedback */
295 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
296 sysInfo->pllExtBusDiv;
297 }
298
299 /* Now calculate the individual clocks */
300 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
301 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
302 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
303 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
304 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
305 sysInfo->freqDDR = sysInfo->freqPLB;
306 sysInfo->freqUART = sysInfo->freqPLB;
307
308 return;
309}
310
311#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200312 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200313void get_sys_info (sys_info_t *sysInfo)
314{
315 unsigned long temp;
316 unsigned long reg;
317 unsigned long lfdiv;
318 unsigned long m;
319 unsigned long prbdv0;
320 /*
321 WARNING: ASSUMES the following:
322 ENG=1
323 PRADV0=1
324 PRBDV0=1
325 */
326
327 /* Decode CPR0_PLLD0 for divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200328 mfcpr(CPR0_PLLD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200329 temp = (reg & PLLD_FWDVA_MASK) >> 16;
330 sysInfo->pllFwdDivA = temp ? temp : 16;
331 temp = (reg & PLLD_FWDVB_MASK) >> 8;
332 sysInfo->pllFwdDivB = temp ? temp: 8 ;
333 temp = (reg & PLLD_FBDV_MASK) >> 24;
334 sysInfo->pllFbkDiv = temp ? temp : 32;
335 lfdiv = reg & PLLD_LFBDV_MASK;
336
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200337 mfcpr(CPR0_OPBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200338 temp = (reg & OPBDDV_MASK) >> 24;
339 sysInfo->pllOpbDiv = temp ? temp : 4;
340
Stefan Roesed1c3b272009-09-09 16:25:29 +0200341 mfcpr(CPR0_PERD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200342 temp = (reg & PERDV_MASK) >> 24;
343 sysInfo->pllExtBusDiv = temp ? temp : 8;
344
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200345 mfcpr(CPR0_PRIMBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200346 temp = (reg & PRBDV_MASK) >> 24;
347 prbdv0 = temp ? temp : 8;
348
Stefan Roesed1c3b272009-09-09 16:25:29 +0200349 mfcpr(CPR0_SPCID, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200350 temp = (reg & SPCID_MASK) >> 24;
351 sysInfo->pllPciDiv = temp ? temp : 4;
352
353 /* Calculate 'M' based on feedback source */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200354 mfsdr(SDR0_SDSTP0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200355 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
356 if (temp == 0) { /* PLL output */
357 /* Figure which pll to use */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200358 mfcpr(CPR0_PLLC, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200359 temp = (reg & PLLC_SRC_MASK) >> 29;
360 if (!temp) /* PLLOUTA */
361 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
362 else /* PLLOUTB */
363 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
364 }
365 else if (temp == 1) /* CPU output */
366 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
367 else /* PerClk */
368 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
369
370 /* Now calculate the individual clocks */
371 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
372 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
373 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
374 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200375 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200376 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200377 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200378
379 /* Figure which timer source to use */
Matthias Fuchs58ea1422009-07-22 17:27:56 +0200380 if (mfspr(SPRN_CCR1) & 0x0080) {
381 /* External Clock, assume same as SYS_CLK */
Stefan Roesec157d8e2005-08-01 16:41:48 +0200382 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
383 if (CONFIG_SYS_CLK_FREQ > temp)
384 sysInfo->freqTmrClk = temp;
385 else
386 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
387 }
388 else /* Internal clock */
389 sysInfo->freqTmrClk = sysInfo->freqProcessor;
390}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200391
Stefan Roesec157d8e2005-08-01 16:41:48 +0200392/********************************************
393 * get_PCI_freq
394 * return PCI bus freq in Hz
395 *********************************************/
396ulong get_PCI_freq (void)
397{
398 sys_info_t sys_info;
399 get_sys_info (&sys_info);
400 return sys_info.freqPCI;
401}
402
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200403#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
404 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000405void get_sys_info (sys_info_t * sysInfo)
406{
407 unsigned long strp0;
408 unsigned long temp;
409 unsigned long m;
410
411 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200412 strp0 = mfdcr( CPC0_STRP0 );
wdenkc6097192002-11-03 00:24:07 +0000413 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
414 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
415 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
416 sysInfo->pllFbkDiv = temp ? temp : 16;
417 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
418 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
419
420 /* Calculate 'M' based on feedback source */
421 if( strp0 & PLLSYS0_EXTSL_MASK )
422 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
423 else
424 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
425
426 /* Now calculate the individual clocks */
427 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
428 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
429 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200430 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
431 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000432 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200433 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200434 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000435}
wdenkba56f622004-02-06 23:19:44 +0000436#else
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200437
438#if !defined(CONFIG_XILINX_440)
wdenkba56f622004-02-06 23:19:44 +0000439void get_sys_info (sys_info_t * sysInfo)
440{
441 unsigned long strp0;
442 unsigned long strp1;
443 unsigned long temp;
444 unsigned long temp1;
445 unsigned long lfdiv;
446 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000447 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000448
Stefan Roese4745aca2007-02-20 10:57:08 +0100449#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200450 unsigned long sys_freq;
451 unsigned long sys_per=0;
452 unsigned long msr;
453 unsigned long pci_clock_per;
454 unsigned long sdr_ddrpll;
455
456 /*-------------------------------------------------------------------------+
457 | Get the system clock period.
458 +-------------------------------------------------------------------------*/
459 sys_per = determine_sysper();
460
461 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
462
463 /*-------------------------------------------------------------------------+
464 | Calculate the system clock speed from the period.
465 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100466 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200467#endif
468
wdenkba56f622004-02-06 23:19:44 +0000469 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200470 mfsdr( SDR0_SDSTP0,strp0 );
471 mfsdr( SDR0_SDSTP1,strp1 );
wdenkba56f622004-02-06 23:19:44 +0000472
473 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
474 sysInfo->pllFwdDivA = temp ? temp : 16 ;
475 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
476 sysInfo->pllFwdDivB = temp ? temp: 8 ;
477 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
478 sysInfo->pllFbkDiv = temp ? temp : 32;
479 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
480 sysInfo->pllOpbDiv = temp ? temp : 4;
481 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
482 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000483 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000484
485 /* Calculate 'M' based on feedback source */
486 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
487 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
488 lfdiv = temp1 ? temp1 : 64;
489 if (temp == 0) { /* PLL output */
490 /* Figure which pll to use */
491 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
492 if (!temp)
493 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
494 else
495 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
496 }
497 else if (temp == 1) /* CPU output */
498 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
499 else /* PerClk */
500 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
501
502 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100503#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200504 sysInfo->freqVCOMhz = (m * sys_freq) ;
505#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100506 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200507#endif
wdenkba56f622004-02-06 23:19:44 +0000508 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000509 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000510 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200511 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000512
Stefan Roese4745aca2007-02-20 10:57:08 +0100513#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200514 /* Determine PCI Clock Period */
515 pci_clock_per = determine_pci_clock_per();
516 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
Stefan Roesed1c3b272009-09-09 16:25:29 +0200517 mfsdr(SDR0_DDR0, sdr_ddrpll);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200518 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
519#endif
520
Stefan Roesefa8aea22007-10-22 07:33:52 +0200521 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200522}
523
524#endif
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200525#endif /* CONFIG_XILINX_440 */
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200526
Stefan Roese4745aca2007-02-20 10:57:08 +0100527#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200528unsigned long determine_sysper(void)
529{
530 unsigned int fpga_clocking_reg;
531 unsigned int master_clock_selection;
532 unsigned long master_clock_per = 0;
533 unsigned long fb_div_selection;
534 unsigned int vco_div_reg_value;
535 unsigned long vco_div_selection;
536 unsigned long sys_per = 0;
537 int extClkVal;
538
539 /*-------------------------------------------------------------------------+
540 | Read FPGA reg 0 and reg 1 to get FPGA reg information
541 +-------------------------------------------------------------------------*/
542 fpga_clocking_reg = in16(FPGA_REG16);
543
544
545 /* Determine Master Clock Source Selection */
546 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
547
548 switch(master_clock_selection) {
549 case FPGA_REG16_MASTER_CLK_66_66:
550 master_clock_per = PERIOD_66_66MHZ;
551 break;
552 case FPGA_REG16_MASTER_CLK_50:
553 master_clock_per = PERIOD_50_00MHZ;
554 break;
555 case FPGA_REG16_MASTER_CLK_33_33:
556 master_clock_per = PERIOD_33_33MHZ;
557 break;
558 case FPGA_REG16_MASTER_CLK_25:
559 master_clock_per = PERIOD_25_00MHZ;
560 break;
561 case FPGA_REG16_MASTER_CLK_EXT:
562 if ((extClkVal==EXTCLK_33_33)
563 && (extClkVal==EXTCLK_50)
564 && (extClkVal==EXTCLK_66_66)
565 && (extClkVal==EXTCLK_83)) {
566 /* calculate master clock period from external clock value */
567 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
568 } else {
569 /* Unsupported */
570 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
571 hang();
572 }
573 break;
574 default:
575 /* Unsupported */
576 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
577 hang();
578 break;
579 }
580
581 /* Determine FB divisors values */
582 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
583 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
584 fb_div_selection = FPGA_FB_DIV_6;
585 else
586 fb_div_selection = FPGA_FB_DIV_12;
587 } else {
588 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
589 fb_div_selection = FPGA_FB_DIV_10;
590 else
591 fb_div_selection = FPGA_FB_DIV_20;
592 }
593
594 /* Determine VCO divisors values */
595 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
596
597 switch(vco_div_reg_value) {
598 case FPGA_REG16_VCO_DIV_4:
599 vco_div_selection = FPGA_VCO_DIV_4;
600 break;
601 case FPGA_REG16_VCO_DIV_6:
602 vco_div_selection = FPGA_VCO_DIV_6;
603 break;
604 case FPGA_REG16_VCO_DIV_8:
605 vco_div_selection = FPGA_VCO_DIV_8;
606 break;
607 case FPGA_REG16_VCO_DIV_10:
608 default:
609 vco_div_selection = FPGA_VCO_DIV_10;
610 break;
611 }
612
613 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
614 switch(master_clock_per) {
615 case PERIOD_25_00MHZ:
616 if (fb_div_selection == FPGA_FB_DIV_12) {
617 if (vco_div_selection == FPGA_VCO_DIV_4)
618 sys_per = PERIOD_75_00MHZ;
619 if (vco_div_selection == FPGA_VCO_DIV_6)
620 sys_per = PERIOD_50_00MHZ;
621 }
622 break;
623 case PERIOD_33_33MHZ:
624 if (fb_div_selection == FPGA_FB_DIV_6) {
625 if (vco_div_selection == FPGA_VCO_DIV_4)
626 sys_per = PERIOD_50_00MHZ;
627 if (vco_div_selection == FPGA_VCO_DIV_6)
628 sys_per = PERIOD_33_33MHZ;
629 }
630 if (fb_div_selection == FPGA_FB_DIV_10) {
631 if (vco_div_selection == FPGA_VCO_DIV_4)
632 sys_per = PERIOD_83_33MHZ;
633 if (vco_div_selection == FPGA_VCO_DIV_10)
634 sys_per = PERIOD_33_33MHZ;
635 }
636 if (fb_div_selection == FPGA_FB_DIV_12) {
637 if (vco_div_selection == FPGA_VCO_DIV_4)
638 sys_per = PERIOD_100_00MHZ;
639 if (vco_div_selection == FPGA_VCO_DIV_6)
640 sys_per = PERIOD_66_66MHZ;
641 if (vco_div_selection == FPGA_VCO_DIV_8)
642 sys_per = PERIOD_50_00MHZ;
643 }
644 break;
645 case PERIOD_50_00MHZ:
646 if (fb_div_selection == FPGA_FB_DIV_6) {
647 if (vco_div_selection == FPGA_VCO_DIV_4)
648 sys_per = PERIOD_75_00MHZ;
649 if (vco_div_selection == FPGA_VCO_DIV_6)
650 sys_per = PERIOD_50_00MHZ;
651 }
652 if (fb_div_selection == FPGA_FB_DIV_10) {
653 if (vco_div_selection == FPGA_VCO_DIV_6)
654 sys_per = PERIOD_83_33MHZ;
655 if (vco_div_selection == FPGA_VCO_DIV_10)
656 sys_per = PERIOD_50_00MHZ;
657 }
658 if (fb_div_selection == FPGA_FB_DIV_12) {
659 if (vco_div_selection == FPGA_VCO_DIV_6)
660 sys_per = PERIOD_100_00MHZ;
661 if (vco_div_selection == FPGA_VCO_DIV_8)
662 sys_per = PERIOD_75_00MHZ;
663 }
664 break;
665 case PERIOD_66_66MHZ:
666 if (fb_div_selection == FPGA_FB_DIV_6) {
667 if (vco_div_selection == FPGA_VCO_DIV_4)
668 sys_per = PERIOD_100_00MHZ;
669 if (vco_div_selection == FPGA_VCO_DIV_6)
670 sys_per = PERIOD_66_66MHZ;
671 if (vco_div_selection == FPGA_VCO_DIV_8)
672 sys_per = PERIOD_50_00MHZ;
673 }
674 if (fb_div_selection == FPGA_FB_DIV_10) {
675 if (vco_div_selection == FPGA_VCO_DIV_8)
676 sys_per = PERIOD_83_33MHZ;
677 if (vco_div_selection == FPGA_VCO_DIV_10)
678 sys_per = PERIOD_66_66MHZ;
679 }
680 if (fb_div_selection == FPGA_FB_DIV_12) {
681 if (vco_div_selection == FPGA_VCO_DIV_8)
682 sys_per = PERIOD_100_00MHZ;
683 }
684 break;
685 default:
686 break;
687 }
688
689 if (sys_per == 0) {
690 /* Other combinations are not supported */
691 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
692 hang();
693 }
694 } else {
695 /* calcul system clock without cheking */
696 /* if engineering option clock no check is selected */
697 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
698 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
699 }
700
701 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200702}
703
704/*-------------------------------------------------------------------------+
705| determine_pci_clock_per.
706+-------------------------------------------------------------------------*/
707unsigned long determine_pci_clock_per(void)
708{
709 unsigned long pci_clock_selection, pci_period;
710
711 /*-------------------------------------------------------------------------+
712 | Read FPGA reg 6 to get PCI 0 FPGA reg information
713 +-------------------------------------------------------------------------*/
714 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
715
716
717 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
718
719 switch (pci_clock_selection) {
720 case FPGA_REG16_PCI0_CLK_133_33:
721 pci_period = PERIOD_133_33MHZ;
722 break;
723 case FPGA_REG16_PCI0_CLK_100:
724 pci_period = PERIOD_100_00MHZ;
725 break;
726 case FPGA_REG16_PCI0_CLK_66_66:
727 pci_period = PERIOD_66_66MHZ;
728 break;
729 default:
730 pci_period = PERIOD_33_33MHZ;;
731 break;
732 }
733
734 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000735}
736#endif
wdenkc6097192002-11-03 00:24:07 +0000737
Michal Simek9fea65a2008-06-24 09:54:09 +0200738#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000739extern void get_sys_info (sys_info_t * sysInfo);
740extern ulong get_PCI_freq (void);
741
Wolfgang Denk7521af12005-10-09 01:04:33 +0200742#elif defined(CONFIG_AP1000)
Stefan Roesefa8aea22007-10-22 07:33:52 +0200743void get_sys_info (sys_info_t * sysInfo)
744{
Wolfgang Denk7521af12005-10-09 01:04:33 +0200745 sysInfo->freqProcessor = 240 * 1000 * 1000;
746 sysInfo->freqPLB = 80 * 1000 * 1000;
747 sysInfo->freqPCI = 33 * 1000 * 1000;
748}
749
wdenkc6097192002-11-03 00:24:07 +0000750#elif defined(CONFIG_405)
751
Stefan Roesefa8aea22007-10-22 07:33:52 +0200752void get_sys_info (sys_info_t * sysInfo)
753{
wdenkc6097192002-11-03 00:24:07 +0000754 sysInfo->freqVCOMhz=3125000;
755 sysInfo->freqProcessor=12*1000*1000;
756 sysInfo->freqPLB=50*1000*1000;
757 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000758}
759
stroeseb867d702003-05-23 11:18:02 +0000760#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200761void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000762{
763 unsigned long pllmr0;
764 unsigned long pllmr1;
765 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
766 unsigned long m;
767 unsigned long pllmr0_ccdv;
768
769 /*
770 * Read PLL Mode registers
771 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200772 pllmr0 = mfdcr (CPC0_PLLMR0);
773 pllmr1 = mfdcr (CPC0_PLLMR1);
stroeseb867d702003-05-23 11:18:02 +0000774
775 /*
776 * Determine forward divider A
777 */
778 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
779
780 /*
781 * Determine forward divider B (should be equal to A)
782 */
783 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
784
785 /*
786 * Determine FBK_DIV.
787 */
788 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200789 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000790 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000791
792 /*
793 * Determine PLB_DIV.
794 */
795 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
796
797 /*
798 * Determine PCI_DIV.
799 */
800 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
801
802 /*
803 * Determine EXTBUS_DIV.
804 */
805 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
806
807 /*
808 * Determine OPB_DIV.
809 */
810 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
811
812 /*
813 * Determine the M factor
814 */
815 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
816
817 /*
818 * Determine VCO clock frequency
819 */
stroeseb39392a2004-12-16 18:13:53 +0000820 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
821 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000822
823 /*
824 * Determine CPU clock frequency
825 */
826 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
827 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000828 /*
829 * This is true if FWDVA == FWDVB:
830 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
831 * / pllmr0_ccdv;
832 */
833 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
834 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000835 } else {
836 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
837 }
838
839 /*
840 * Determine PLB clock frequency
841 */
842 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200843
844 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200845
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200846 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
847
Stefan Roesefa8aea22007-10-22 07:33:52 +0200848 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000849}
850
851
852/********************************************
stroeseb867d702003-05-23 11:18:02 +0000853 * get_PCI_freq
854 * return PCI bus freq in Hz
855 *********************************************/
856ulong get_PCI_freq (void)
857{
858 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200859 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000860
861 get_sys_info (&sys_info);
862 val = sys_info.freqPLB / sys_info.pllPciDiv;
863 return val;
864}
865
Stefan Roesee01bd212007-03-21 13:38:59 +0100866#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200867void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100868{
869 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200870 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100871 unsigned long cpr_primad;
872 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
873 unsigned long primad_cpudv;
874 unsigned long m;
Stefan Roese95a4a592009-09-11 17:07:55 +0200875 unsigned long plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100876
877 /*
878 * Read PLL Mode registers
879 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200880 mfcpr(CPR0_PLLD, cpr_plld);
881 mfcpr(CPR0_PLLC, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100882
883 /*
884 * Determine forward divider A
885 */
886 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
887
888 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200889 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100890 */
891 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200892 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100893 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100894
895 /*
896 * Determine FBK_DIV.
897 */
898 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200899 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100900 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100901
902 /*
903 * Read CPR_PRIMAD register
904 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200905 mfcpr(CPC0_PRIMAD, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200906
Stefan Roesee01bd212007-03-21 13:38:59 +0100907 /*
908 * Determine PLB_DIV.
909 */
910 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200911 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100912 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100913
914 /*
915 * Determine EXTBUS_DIV.
916 */
917 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200918 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100919 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100920
921 /*
922 * Determine OPB_DIV.
923 */
924 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200925 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100926 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100927
928 /*
929 * Determine the M factor
930 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200931 if (cpr_pllc & PLLC_SRC_MASK)
932 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
933 else
934 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100935
936 /*
937 * Determine VCO clock frequency
938 */
939 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
940 (unsigned long long)sysClkPeriodPs;
941
942 /*
943 * Determine CPU clock frequency
944 */
945 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200946 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100947 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100948
Stefan Roese273db7e2007-08-13 09:05:33 +0200949 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
950 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100951
952 /*
953 * Determine PLB clock frequency
954 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200955 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
956 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200957
Stefan Roesee67af442009-09-14 11:13:34 +0200958 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
959 sysInfo->pllOpbDiv;
960
Stefan Roesedbbd1252007-10-05 17:10:59 +0200961 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
962 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200963
Stefan Roese95a4a592009-09-11 17:07:55 +0200964 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
965 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
966 sysInfo->pllFwdDivB);
967 sysInfo->freqUART = plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100968}
969
Stefan Roesedbbd1252007-10-05 17:10:59 +0200970#elif defined(CONFIG_405EX)
971
972/*
973 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
974 * We need the specs!!!!
975 */
976static unsigned char get_fbdv(unsigned char index)
977{
978 unsigned char ret = 0;
979 /* This is table should be 256 bytes.
980 * Only take first 52 values.
981 */
982 unsigned char fbdv_tb[] = {
983 0x00, 0xff, 0x7f, 0xfd,
984 0x7a, 0xf5, 0x6a, 0xd5,
985 0x2a, 0xd4, 0x29, 0xd3,
986 0x26, 0xcc, 0x19, 0xb3,
987 0x67, 0xce, 0x1d, 0xbb,
988 0x77, 0xee, 0x5d, 0xba,
989 0x74, 0xe9, 0x52, 0xa5,
990 0x4b, 0x96, 0x2c, 0xd8,
991 0x31, 0xe3, 0x46, 0x8d,
992 0x1b, 0xb7, 0x6f, 0xde,
993 0x3d, 0xfb, 0x76, 0xed,
994 0x5a, 0xb5, 0x6b, 0xd6,
995 0x2d, 0xdb, 0x36, 0xec,
996
997 };
998
999 if ((index & 0x7f) == 0)
1000 return 1;
1001 while (ret < sizeof (fbdv_tb)) {
1002 if (fbdv_tb[ret] == index)
1003 break;
1004 ret++;
1005 }
1006 ret++;
1007
1008 return ret;
1009}
1010
1011#define PLL_FBK_PLL_LOCAL 0
1012#define PLL_FBK_CPU 1
1013#define PLL_FBK_PERCLK 5
1014
1015void get_sys_info (sys_info_t * sysInfo)
1016{
1017 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1018 unsigned long m = 1;
1019 unsigned int tmp;
1020 unsigned char fwdva[16] = {
1021 1, 2, 14, 9, 4, 11, 16, 13,
1022 12, 5, 6, 15, 10, 7, 8, 3,
1023 };
1024 unsigned char sel, cpudv0, plb2xDiv;
1025
Stefan Roesed1c3b272009-09-09 16:25:29 +02001026 mfcpr(CPR0_PLLD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001027
1028 /*
1029 * Determine forward divider A
1030 */
1031 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1032
1033 /*
1034 * Determine FBK_DIV.
1035 */
1036 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1037
1038 /*
1039 * Determine PLBDV0
1040 */
1041 sysInfo->pllPlbDiv = 2;
1042
1043 /*
1044 * Determine PERDV0
1045 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001046 mfcpr(CPR0_PERD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001047 tmp = (tmp >> 24) & 0x03;
1048 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1049
1050 /*
1051 * Determine OPBDV0
1052 */
Niklaus Gigerddc922f2009-10-04 20:04:20 +02001053 mfcpr(CPR0_OPBD0, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001054 tmp = (tmp >> 24) & 0x03;
1055 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1056
1057 /* Determine PLB2XDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001058 mfcpr(CPR0_PLBD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001059 tmp = (tmp >> 16) & 0x07;
1060 plb2xDiv = (tmp == 0) ? 8 : tmp;
1061
1062 /* Determine CPUDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001063 mfcpr(CPR0_CPUD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001064 tmp = (tmp >> 24) & 0x07;
1065 cpudv0 = (tmp == 0) ? 8 : tmp;
1066
1067 /* Determine SEL(5:7) in CPR0_PLLC */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001068 mfcpr(CPR0_PLLC, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001069 sel = (tmp >> 24) & 0x07;
1070
1071 /*
1072 * Determine the M factor
1073 * PLL local: M = FBDV
1074 * CPU clock: M = FBDV * FWDVA * CPUDV0
1075 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1076 *
1077 */
1078 switch (sel) {
1079 case PLL_FBK_CPU:
1080 m = sysInfo->pllFwdDiv * cpudv0;
1081 break;
1082 case PLL_FBK_PERCLK:
1083 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1084 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1085 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001086 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001087 break;
1088 default:
1089 printf("%s unknown m\n", __FUNCTION__);
1090 return;
1091
1092 }
1093 m *= sysInfo->pllFbkDiv;
1094
1095 /*
1096 * Determine VCO clock frequency
1097 */
1098 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1099 (unsigned long long)sysClkPeriodPs;
1100
1101 /*
1102 * Determine CPU clock frequency
1103 */
1104 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1105
1106 /*
1107 * Determine PLB clock frequency, ddr1x should be the same
1108 */
1109 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1110 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1111 sysInfo->freqDDR = sysInfo->freqPLB;
1112 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001113 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001114}
1115
wdenkc6097192002-11-03 00:24:07 +00001116#endif
1117
1118int get_clocks (void)
1119{
Stefan Roesee01bd212007-03-21 13:38:59 +01001120#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1121 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001122 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1123 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001124 sys_info_t sys_info;
1125
1126 get_sys_info (&sys_info);
1127 gd->cpu_clk = sys_info.freqProcessor;
1128 gd->bus_clk = sys_info.freqPLB;
1129
1130#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1131
1132#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001133 gd->cpu_clk = 66000000;
1134 gd->bus_clk = 66000000;
1135#endif
1136 return (0);
1137}
1138
1139
1140/********************************************
1141 * get_bus_freq
1142 * return PLB bus freq in Hz
1143 *********************************************/
1144ulong get_bus_freq (ulong dummy)
1145{
1146 ulong val;
1147
Stefan Roesee01bd212007-03-21 13:38:59 +01001148#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1149 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001150 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1151 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001152 sys_info_t sys_info;
1153
1154 get_sys_info (&sys_info);
1155 val = sys_info.freqPLB;
1156
1157#elif defined(CONFIG_IOP480)
1158
1159 val = 66;
1160
1161#else
1162# error get_bus_freq() not implemented
1163#endif
1164
1165 return val;
1166}
Stefan Roesee67af442009-09-14 11:13:34 +02001167
1168#if !defined(CONFIG_IOP480)
1169ulong get_OPB_freq (void)
1170{
1171 PPC4xx_SYS_INFO sys_info;
1172
1173 get_sys_info (&sys_info);
1174
1175 return sys_info.freqOPB;
1176}
1177#endif