blob: d21bd82dc6f43abf0bcbe0d68dda90131cb979da [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
Stefan Roesecc019d12008-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 Denk6405a152006-03-31 18:32:53 +020029DECLARE_GLOBAL_DATA_PTR;
wdenkc6097192002-11-03 00:24:07 +000030
31#define ONE_BILLION 1000000000
Marian Balakowicz49d0eee2006-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 Roesecc019d12008-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 Roeseedd73f22007-10-21 08:12:41 +020042void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
wdenkc6097192002-11-03 00:24:07 +000043{
44 unsigned long pllmr;
45 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
46 uint pvr = get_pvr();
47 unsigned long psr;
48 unsigned long m;
49
50 /*
51 * Read PLL Mode register
52 */
53 pllmr = mfdcr (pllmd);
54
55 /*
56 * Read Pin Strapping register
57 */
58 psr = mfdcr (strap);
59
60 /*
61 * Determine FWD_DIV.
62 */
63 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
64
65 /*
66 * Determine FBK_DIV.
67 */
68 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
69 if (sysInfo->pllFbkDiv == 0) {
70 sysInfo->pllFbkDiv = 16;
71 }
72
73 /*
74 * Determine PLB_DIV.
75 */
76 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
77
78 /*
79 * Determine PCI_DIV.
80 */
81 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
82
83 /*
84 * Determine EXTBUS_DIV.
85 */
86 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
87
88 /*
89 * Determine OPB_DIV.
90 */
91 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
92
93 /*
94 * Check if PPC405GPr used (mask minor revision field)
95 */
stroeseff90f802003-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
stroese5d542f12004-12-16 18:13:53 +0000141 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
142 (unsigned long long)sysClkPeriodPs;
143 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
144 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
wdenkc6097192002-11-03 00:24:07 +0000145 } else {
146 /*
147 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
148 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
149 * to make sure it is within the proper range.
150 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
151 * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding.
152 */
153 if (sysInfo->pllFwdDiv == 1) {
154 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
155 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
156 } else {
stroese5d542f12004-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 Roese628d3922007-10-22 07:33:52 +0200167
Matthias Fuchs3c70edc2008-04-18 17:24:32 +0200168 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
169
Stefan Roese628d3922007-10-22 07:33:52 +0200170 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000171}
172
173
174/********************************************
175 * get_OPB_freq
176 * return OPB bus freq in Hz
177 *********************************************/
178ulong get_OPB_freq (void)
179{
180 ulong val = 0;
181
Stefan Roeseedd73f22007-10-21 08:12:41 +0200182 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000183
184 get_sys_info (&sys_info);
185 val = sys_info.freqPLB / sys_info.pllOpbDiv;
186
187 return val;
188}
189
190
191/********************************************
192 * get_PCI_freq
193 * return PCI bus freq in Hz
194 *********************************************/
195ulong get_PCI_freq (void)
196{
197 ulong val;
Stefan Roeseedd73f22007-10-21 08:12:41 +0200198 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000199
200 get_sys_info (&sys_info);
201 val = sys_info.freqPLB / sys_info.pllPciDiv;
202 return val;
203}
204
205
206#elif defined(CONFIG_440)
Stefan Roese326c9712005-08-01 16:41:48 +0200207
Feng Kan224bc962008-07-08 22:47:31 -0700208#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
209 defined(CONFIG_460SX)
Stefan Roesecc019d12008-03-11 15:05:50 +0100210static u8 pll_fwdv_multi_bits[] = {
211 /* values for: 1 - 16 */
212 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
213 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
214};
215
216u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
217{
218 u32 index;
219
220 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
221 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
222 return index + 1;
223
224 return 0;
225}
226
227static u8 pll_fbdv_multi_bits[] = {
228 /* values for: 1 - 100 */
229 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
230 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
231 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
232 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
233 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
234 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
235 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
236 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
237 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
238 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
239 /* values for: 101 - 200 */
240 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
241 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchell05e89742008-05-07 09:00:23 -0700242 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roesecc019d12008-03-11 15:05:50 +0100243 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
244 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
245 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
246 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
247 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
248 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
249 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
250 /* values for: 201 - 255 */
251 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
252 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
253 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
254 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
255 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
256 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
257};
258
259u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
260{
261 u32 index;
262
263 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
264 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
265 return index + 1;
266
267 return 0;
268}
269
270/*
271 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
272 * with latest EAS
273 */
274void get_sys_info (sys_info_t * sysInfo)
275{
276 unsigned long strp0;
277 unsigned long strp1;
278 unsigned long temp;
279 unsigned long m;
280 unsigned long plbedv0;
281
282 /* Extract configured divisors */
283 mfsdr(sdr_sdstp0, strp0);
284 mfsdr(sdr_sdstp1, strp1);
285
286 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
287 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
288
289 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
290 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
291
292 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
293 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
294
295 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
296 sysInfo->pllOpbDiv = temp ? temp : 4;
297
298 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
299 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
300 sysInfo->pllExtBusDiv = temp ? temp : 4;
301
302 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
303 plbedv0 = temp ? temp: 8;
304
305 /* Calculate 'M' based on feedback source */
306 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
307 if (temp == 0) {
308 /* PLL internal feedback */
309 m = sysInfo->pllFbkDiv;
310 } else {
311 /* PLL PerClk feedback */
312 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
313 sysInfo->pllExtBusDiv;
314 }
315
316 /* Now calculate the individual clocks */
317 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
318 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
319 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
320 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
321 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
322 sysInfo->freqDDR = sysInfo->freqPLB;
323 sysInfo->freqUART = sysInfo->freqPLB;
324
325 return;
326}
327
328#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese42fbddd2006-09-07 11:51:23 +0200329 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roese326c9712005-08-01 16:41:48 +0200330void get_sys_info (sys_info_t *sysInfo)
331{
332 unsigned long temp;
333 unsigned long reg;
334 unsigned long lfdiv;
335 unsigned long m;
336 unsigned long prbdv0;
337 /*
338 WARNING: ASSUMES the following:
339 ENG=1
340 PRADV0=1
341 PRBDV0=1
342 */
343
344 /* Decode CPR0_PLLD0 for divisors */
Stefan Roeseedd73f22007-10-21 08:12:41 +0200345 mfcpr(clk_plld, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200346 temp = (reg & PLLD_FWDVA_MASK) >> 16;
347 sysInfo->pllFwdDivA = temp ? temp : 16;
348 temp = (reg & PLLD_FWDVB_MASK) >> 8;
349 sysInfo->pllFwdDivB = temp ? temp: 8 ;
350 temp = (reg & PLLD_FBDV_MASK) >> 24;
351 sysInfo->pllFbkDiv = temp ? temp : 32;
352 lfdiv = reg & PLLD_LFBDV_MASK;
353
Stefan Roeseedd73f22007-10-21 08:12:41 +0200354 mfcpr(clk_opbd, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200355 temp = (reg & OPBDDV_MASK) >> 24;
356 sysInfo->pllOpbDiv = temp ? temp : 4;
357
Stefan Roeseedd73f22007-10-21 08:12:41 +0200358 mfcpr(clk_perd, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200359 temp = (reg & PERDV_MASK) >> 24;
360 sysInfo->pllExtBusDiv = temp ? temp : 8;
361
Stefan Roeseedd73f22007-10-21 08:12:41 +0200362 mfcpr(clk_primbd, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200363 temp = (reg & PRBDV_MASK) >> 24;
364 prbdv0 = temp ? temp : 8;
365
Stefan Roeseedd73f22007-10-21 08:12:41 +0200366 mfcpr(clk_spcid, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200367 temp = (reg & SPCID_MASK) >> 24;
368 sysInfo->pllPciDiv = temp ? temp : 4;
369
370 /* Calculate 'M' based on feedback source */
371 mfsdr(sdr_sdstp0, reg);
372 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
373 if (temp == 0) { /* PLL output */
374 /* Figure which pll to use */
Stefan Roeseedd73f22007-10-21 08:12:41 +0200375 mfcpr(clk_pllc, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200376 temp = (reg & PLLC_SRC_MASK) >> 29;
377 if (!temp) /* PLLOUTA */
378 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
379 else /* PLLOUTB */
380 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
381 }
382 else if (temp == 1) /* CPU output */
383 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
384 else /* PerClk */
385 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
386
387 /* Now calculate the individual clocks */
388 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
389 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
390 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
391 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200392 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roese326c9712005-08-01 16:41:48 +0200393 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200394 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roese326c9712005-08-01 16:41:48 +0200395
396 /* Figure which timer source to use */
397 if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */
398 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
399 if (CONFIG_SYS_CLK_FREQ > temp)
400 sysInfo->freqTmrClk = temp;
401 else
402 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
403 }
404 else /* Internal clock */
405 sysInfo->freqTmrClk = sysInfo->freqProcessor;
406}
Stefan Roese628d3922007-10-22 07:33:52 +0200407
Stefan Roese326c9712005-08-01 16:41:48 +0200408/********************************************
409 * get_PCI_freq
410 * return PCI bus freq in Hz
411 *********************************************/
412ulong get_PCI_freq (void)
413{
414 sys_info_t sys_info;
415 get_sys_info (&sys_info);
416 return sys_info.freqPCI;
417}
418
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200419#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
420 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000421void get_sys_info (sys_info_t * sysInfo)
422{
423 unsigned long strp0;
424 unsigned long temp;
425 unsigned long m;
426
427 /* Extract configured divisors */
428 strp0 = mfdcr( cpc0_strp0 );
429 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
430 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
431 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
432 sysInfo->pllFbkDiv = temp ? temp : 16;
433 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
434 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
435
436 /* Calculate 'M' based on feedback source */
437 if( strp0 & PLLSYS0_EXTSL_MASK )
438 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
439 else
440 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
441
442 /* Now calculate the individual clocks */
443 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
444 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
445 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roese326c9712005-08-01 16:41:48 +0200446 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
447 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000448 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200449 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200450 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000451}
wdenk544e9732004-02-06 23:19:44 +0000452#else
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200453
454#if !defined(CONFIG_XILINX_440)
wdenk544e9732004-02-06 23:19:44 +0000455void get_sys_info (sys_info_t * sysInfo)
456{
457 unsigned long strp0;
458 unsigned long strp1;
459 unsigned long temp;
460 unsigned long temp1;
461 unsigned long lfdiv;
462 unsigned long m;
wdenkc35ba4e2004-03-14 22:25:36 +0000463 unsigned long prbdv0;
wdenk544e9732004-02-06 23:19:44 +0000464
Stefan Roesea8856e32007-02-20 10:57:08 +0100465#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200466 unsigned long sys_freq;
467 unsigned long sys_per=0;
468 unsigned long msr;
469 unsigned long pci_clock_per;
470 unsigned long sdr_ddrpll;
471
472 /*-------------------------------------------------------------------------+
473 | Get the system clock period.
474 +-------------------------------------------------------------------------*/
475 sys_per = determine_sysper();
476
477 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
478
479 /*-------------------------------------------------------------------------+
480 | Calculate the system clock speed from the period.
481 +-------------------------------------------------------------------------*/
Stefan Roesea8856e32007-02-20 10:57:08 +0100482 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200483#endif
484
wdenk544e9732004-02-06 23:19:44 +0000485 /* Extract configured divisors */
486 mfsdr( sdr_sdstp0,strp0 );
487 mfsdr( sdr_sdstp1,strp1 );
488
489 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
490 sysInfo->pllFwdDivA = temp ? temp : 16 ;
491 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
492 sysInfo->pllFwdDivB = temp ? temp: 8 ;
493 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
494 sysInfo->pllFbkDiv = temp ? temp : 32;
495 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
496 sysInfo->pllOpbDiv = temp ? temp : 4;
497 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
498 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk00fe1612004-03-14 00:07:33 +0000499 prbdv0 = (strp0 >> 2) & 0x7;
wdenk544e9732004-02-06 23:19:44 +0000500
501 /* Calculate 'M' based on feedback source */
502 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
503 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
504 lfdiv = temp1 ? temp1 : 64;
505 if (temp == 0) { /* PLL output */
506 /* Figure which pll to use */
507 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
508 if (!temp)
509 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
510 else
511 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
512 }
513 else if (temp == 1) /* CPU output */
514 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
515 else /* PerClk */
516 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
517
518 /* Now calculate the individual clocks */
Stefan Roesea8856e32007-02-20 10:57:08 +0100519#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200520 sysInfo->freqVCOMhz = (m * sys_freq) ;
521#else
Stefan Roesea8856e32007-02-20 10:57:08 +0100522 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200523#endif
wdenk544e9732004-02-06 23:19:44 +0000524 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk00fe1612004-03-14 00:07:33 +0000525 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenk544e9732004-02-06 23:19:44 +0000526 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200527 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenk544e9732004-02-06 23:19:44 +0000528
Stefan Roesea8856e32007-02-20 10:57:08 +0100529#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200530 /* Determine PCI Clock Period */
531 pci_clock_per = determine_pci_clock_per();
532 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
533 mfsdr(sdr_ddr0, sdr_ddrpll);
534 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
535#endif
536
Stefan Roese628d3922007-10-22 07:33:52 +0200537 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200538}
539
540#endif
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200541#endif /* CONFIG_XILINX_440 */
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200542
Stefan Roesea8856e32007-02-20 10:57:08 +0100543#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200544unsigned long determine_sysper(void)
545{
546 unsigned int fpga_clocking_reg;
547 unsigned int master_clock_selection;
548 unsigned long master_clock_per = 0;
549 unsigned long fb_div_selection;
550 unsigned int vco_div_reg_value;
551 unsigned long vco_div_selection;
552 unsigned long sys_per = 0;
553 int extClkVal;
554
555 /*-------------------------------------------------------------------------+
556 | Read FPGA reg 0 and reg 1 to get FPGA reg information
557 +-------------------------------------------------------------------------*/
558 fpga_clocking_reg = in16(FPGA_REG16);
559
560
561 /* Determine Master Clock Source Selection */
562 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
563
564 switch(master_clock_selection) {
565 case FPGA_REG16_MASTER_CLK_66_66:
566 master_clock_per = PERIOD_66_66MHZ;
567 break;
568 case FPGA_REG16_MASTER_CLK_50:
569 master_clock_per = PERIOD_50_00MHZ;
570 break;
571 case FPGA_REG16_MASTER_CLK_33_33:
572 master_clock_per = PERIOD_33_33MHZ;
573 break;
574 case FPGA_REG16_MASTER_CLK_25:
575 master_clock_per = PERIOD_25_00MHZ;
576 break;
577 case FPGA_REG16_MASTER_CLK_EXT:
578 if ((extClkVal==EXTCLK_33_33)
579 && (extClkVal==EXTCLK_50)
580 && (extClkVal==EXTCLK_66_66)
581 && (extClkVal==EXTCLK_83)) {
582 /* calculate master clock period from external clock value */
583 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
584 } else {
585 /* Unsupported */
586 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
587 hang();
588 }
589 break;
590 default:
591 /* Unsupported */
592 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
593 hang();
594 break;
595 }
596
597 /* Determine FB divisors values */
598 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
599 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
600 fb_div_selection = FPGA_FB_DIV_6;
601 else
602 fb_div_selection = FPGA_FB_DIV_12;
603 } else {
604 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
605 fb_div_selection = FPGA_FB_DIV_10;
606 else
607 fb_div_selection = FPGA_FB_DIV_20;
608 }
609
610 /* Determine VCO divisors values */
611 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
612
613 switch(vco_div_reg_value) {
614 case FPGA_REG16_VCO_DIV_4:
615 vco_div_selection = FPGA_VCO_DIV_4;
616 break;
617 case FPGA_REG16_VCO_DIV_6:
618 vco_div_selection = FPGA_VCO_DIV_6;
619 break;
620 case FPGA_REG16_VCO_DIV_8:
621 vco_div_selection = FPGA_VCO_DIV_8;
622 break;
623 case FPGA_REG16_VCO_DIV_10:
624 default:
625 vco_div_selection = FPGA_VCO_DIV_10;
626 break;
627 }
628
629 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
630 switch(master_clock_per) {
631 case PERIOD_25_00MHZ:
632 if (fb_div_selection == FPGA_FB_DIV_12) {
633 if (vco_div_selection == FPGA_VCO_DIV_4)
634 sys_per = PERIOD_75_00MHZ;
635 if (vco_div_selection == FPGA_VCO_DIV_6)
636 sys_per = PERIOD_50_00MHZ;
637 }
638 break;
639 case PERIOD_33_33MHZ:
640 if (fb_div_selection == FPGA_FB_DIV_6) {
641 if (vco_div_selection == FPGA_VCO_DIV_4)
642 sys_per = PERIOD_50_00MHZ;
643 if (vco_div_selection == FPGA_VCO_DIV_6)
644 sys_per = PERIOD_33_33MHZ;
645 }
646 if (fb_div_selection == FPGA_FB_DIV_10) {
647 if (vco_div_selection == FPGA_VCO_DIV_4)
648 sys_per = PERIOD_83_33MHZ;
649 if (vco_div_selection == FPGA_VCO_DIV_10)
650 sys_per = PERIOD_33_33MHZ;
651 }
652 if (fb_div_selection == FPGA_FB_DIV_12) {
653 if (vco_div_selection == FPGA_VCO_DIV_4)
654 sys_per = PERIOD_100_00MHZ;
655 if (vco_div_selection == FPGA_VCO_DIV_6)
656 sys_per = PERIOD_66_66MHZ;
657 if (vco_div_selection == FPGA_VCO_DIV_8)
658 sys_per = PERIOD_50_00MHZ;
659 }
660 break;
661 case PERIOD_50_00MHZ:
662 if (fb_div_selection == FPGA_FB_DIV_6) {
663 if (vco_div_selection == FPGA_VCO_DIV_4)
664 sys_per = PERIOD_75_00MHZ;
665 if (vco_div_selection == FPGA_VCO_DIV_6)
666 sys_per = PERIOD_50_00MHZ;
667 }
668 if (fb_div_selection == FPGA_FB_DIV_10) {
669 if (vco_div_selection == FPGA_VCO_DIV_6)
670 sys_per = PERIOD_83_33MHZ;
671 if (vco_div_selection == FPGA_VCO_DIV_10)
672 sys_per = PERIOD_50_00MHZ;
673 }
674 if (fb_div_selection == FPGA_FB_DIV_12) {
675 if (vco_div_selection == FPGA_VCO_DIV_6)
676 sys_per = PERIOD_100_00MHZ;
677 if (vco_div_selection == FPGA_VCO_DIV_8)
678 sys_per = PERIOD_75_00MHZ;
679 }
680 break;
681 case PERIOD_66_66MHZ:
682 if (fb_div_selection == FPGA_FB_DIV_6) {
683 if (vco_div_selection == FPGA_VCO_DIV_4)
684 sys_per = PERIOD_100_00MHZ;
685 if (vco_div_selection == FPGA_VCO_DIV_6)
686 sys_per = PERIOD_66_66MHZ;
687 if (vco_div_selection == FPGA_VCO_DIV_8)
688 sys_per = PERIOD_50_00MHZ;
689 }
690 if (fb_div_selection == FPGA_FB_DIV_10) {
691 if (vco_div_selection == FPGA_VCO_DIV_8)
692 sys_per = PERIOD_83_33MHZ;
693 if (vco_div_selection == FPGA_VCO_DIV_10)
694 sys_per = PERIOD_66_66MHZ;
695 }
696 if (fb_div_selection == FPGA_FB_DIV_12) {
697 if (vco_div_selection == FPGA_VCO_DIV_8)
698 sys_per = PERIOD_100_00MHZ;
699 }
700 break;
701 default:
702 break;
703 }
704
705 if (sys_per == 0) {
706 /* Other combinations are not supported */
707 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
708 hang();
709 }
710 } else {
711 /* calcul system clock without cheking */
712 /* if engineering option clock no check is selected */
713 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
714 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
715 }
716
717 return(sys_per);
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200718}
719
720/*-------------------------------------------------------------------------+
721| determine_pci_clock_per.
722+-------------------------------------------------------------------------*/
723unsigned long determine_pci_clock_per(void)
724{
725 unsigned long pci_clock_selection, pci_period;
726
727 /*-------------------------------------------------------------------------+
728 | Read FPGA reg 6 to get PCI 0 FPGA reg information
729 +-------------------------------------------------------------------------*/
730 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
731
732
733 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
734
735 switch (pci_clock_selection) {
736 case FPGA_REG16_PCI0_CLK_133_33:
737 pci_period = PERIOD_133_33MHZ;
738 break;
739 case FPGA_REG16_PCI0_CLK_100:
740 pci_period = PERIOD_100_00MHZ;
741 break;
742 case FPGA_REG16_PCI0_CLK_66_66:
743 pci_period = PERIOD_66_66MHZ;
744 break;
745 default:
746 pci_period = PERIOD_33_33MHZ;;
747 break;
748 }
749
750 return(pci_period);
wdenk544e9732004-02-06 23:19:44 +0000751}
752#endif
wdenkc6097192002-11-03 00:24:07 +0000753
754ulong get_OPB_freq (void)
755{
756
757 sys_info_t sys_info;
758 get_sys_info (&sys_info);
759 return sys_info.freqOPB;
760}
761
Michal Simek594c7b52008-06-24 09:54:09 +0200762#elif defined(CONFIG_XILINX_405)
wdenke537b3b2004-02-23 23:54:43 +0000763extern void get_sys_info (sys_info_t * sysInfo);
764extern ulong get_PCI_freq (void);
765
Wolfgang Denk56811f62005-10-09 01:04:33 +0200766#elif defined(CONFIG_AP1000)
Stefan Roese628d3922007-10-22 07:33:52 +0200767void get_sys_info (sys_info_t * sysInfo)
768{
Wolfgang Denk56811f62005-10-09 01:04:33 +0200769 sysInfo->freqProcessor = 240 * 1000 * 1000;
770 sysInfo->freqPLB = 80 * 1000 * 1000;
771 sysInfo->freqPCI = 33 * 1000 * 1000;
772}
773
wdenkc6097192002-11-03 00:24:07 +0000774#elif defined(CONFIG_405)
775
Stefan Roese628d3922007-10-22 07:33:52 +0200776void get_sys_info (sys_info_t * sysInfo)
777{
wdenkc6097192002-11-03 00:24:07 +0000778 sysInfo->freqVCOMhz=3125000;
779 sysInfo->freqProcessor=12*1000*1000;
780 sysInfo->freqPLB=50*1000*1000;
781 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000782}
783
stroese434979e2003-05-23 11:18:02 +0000784#elif defined(CONFIG_405EP)
Stefan Roeseedd73f22007-10-21 08:12:41 +0200785void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroese434979e2003-05-23 11:18:02 +0000786{
787 unsigned long pllmr0;
788 unsigned long pllmr1;
789 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
790 unsigned long m;
791 unsigned long pllmr0_ccdv;
792
793 /*
794 * Read PLL Mode registers
795 */
796 pllmr0 = mfdcr (cpc0_pllmr0);
797 pllmr1 = mfdcr (cpc0_pllmr1);
798
799 /*
800 * Determine forward divider A
801 */
802 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
803
804 /*
805 * Determine forward divider B (should be equal to A)
806 */
807 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
808
809 /*
810 * Determine FBK_DIV.
811 */
812 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roese628d3922007-10-22 07:33:52 +0200813 if (sysInfo->pllFbkDiv == 0)
stroese434979e2003-05-23 11:18:02 +0000814 sysInfo->pllFbkDiv = 16;
stroese434979e2003-05-23 11:18:02 +0000815
816 /*
817 * Determine PLB_DIV.
818 */
819 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
820
821 /*
822 * Determine PCI_DIV.
823 */
824 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
825
826 /*
827 * Determine EXTBUS_DIV.
828 */
829 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
830
831 /*
832 * Determine OPB_DIV.
833 */
834 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
835
836 /*
837 * Determine the M factor
838 */
839 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
840
841 /*
842 * Determine VCO clock frequency
843 */
stroese5d542f12004-12-16 18:13:53 +0000844 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
845 (unsigned long long)sysClkPeriodPs;
stroese434979e2003-05-23 11:18:02 +0000846
847 /*
848 * Determine CPU clock frequency
849 */
850 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
851 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenk99874b42004-07-01 21:40:08 +0000852 /*
853 * This is true if FWDVA == FWDVB:
854 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
855 * / pllmr0_ccdv;
856 */
857 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
858 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroese434979e2003-05-23 11:18:02 +0000859 } else {
860 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
861 }
862
863 /*
864 * Determine PLB clock frequency
865 */
866 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200867
868 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200869
870 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroese434979e2003-05-23 11:18:02 +0000871}
872
873
874/********************************************
875 * get_OPB_freq
876 * return OPB bus freq in Hz
877 *********************************************/
878ulong get_OPB_freq (void)
879{
880 ulong val = 0;
881
Stefan Roeseedd73f22007-10-21 08:12:41 +0200882 PPC4xx_SYS_INFO sys_info;
stroese434979e2003-05-23 11:18:02 +0000883
884 get_sys_info (&sys_info);
885 val = sys_info.freqPLB / sys_info.pllOpbDiv;
886
887 return val;
888}
889
890
891/********************************************
892 * get_PCI_freq
893 * return PCI bus freq in Hz
894 *********************************************/
895ulong get_PCI_freq (void)
896{
897 ulong val;
Stefan Roeseedd73f22007-10-21 08:12:41 +0200898 PPC4xx_SYS_INFO sys_info;
stroese434979e2003-05-23 11:18:02 +0000899
900 get_sys_info (&sys_info);
901 val = sys_info.freqPLB / sys_info.pllPciDiv;
902 return val;
903}
904
Stefan Roese17ffbc82007-03-21 13:38:59 +0100905#elif defined(CONFIG_405EZ)
Stefan Roeseedd73f22007-10-21 08:12:41 +0200906void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100907{
908 unsigned long cpr_plld;
Stefan Roese87476ba2007-08-13 09:05:33 +0200909 unsigned long cpr_pllc;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100910 unsigned long cpr_primad;
911 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
912 unsigned long primad_cpudv;
913 unsigned long m;
914
915 /*
916 * Read PLL Mode registers
917 */
918 mfcpr(cprplld, cpr_plld);
Stefan Roese87476ba2007-08-13 09:05:33 +0200919 mfcpr(cprpllc, cpr_pllc);
Stefan Roese17ffbc82007-03-21 13:38:59 +0100920
921 /*
922 * Determine forward divider A
923 */
924 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
925
926 /*
Stefan Roese87476ba2007-08-13 09:05:33 +0200927 * Determine forward divider B
Stefan Roese17ffbc82007-03-21 13:38:59 +0100928 */
929 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese87476ba2007-08-13 09:05:33 +0200930 if (sysInfo->pllFwdDivB == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100931 sysInfo->pllFwdDivB = 8;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100932
933 /*
934 * Determine FBK_DIV.
935 */
936 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese87476ba2007-08-13 09:05:33 +0200937 if (sysInfo->pllFbkDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100938 sysInfo->pllFbkDiv = 256;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100939
940 /*
941 * Read CPR_PRIMAD register
942 */
943 mfcpr(cprprimad, cpr_primad);
Stefan Roese628d3922007-10-22 07:33:52 +0200944
Stefan Roese17ffbc82007-03-21 13:38:59 +0100945 /*
946 * Determine PLB_DIV.
947 */
948 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese87476ba2007-08-13 09:05:33 +0200949 if (sysInfo->pllPlbDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100950 sysInfo->pllPlbDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100951
952 /*
953 * Determine EXTBUS_DIV.
954 */
955 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese87476ba2007-08-13 09:05:33 +0200956 if (sysInfo->pllExtBusDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100957 sysInfo->pllExtBusDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100958
959 /*
960 * Determine OPB_DIV.
961 */
962 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese87476ba2007-08-13 09:05:33 +0200963 if (sysInfo->pllOpbDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100964 sysInfo->pllOpbDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100965
966 /*
967 * Determine the M factor
968 */
Stefan Roese87476ba2007-08-13 09:05:33 +0200969 if (cpr_pllc & PLLC_SRC_MASK)
970 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
971 else
972 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100973
974 /*
975 * Determine VCO clock frequency
976 */
977 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
978 (unsigned long long)sysClkPeriodPs;
979
980 /*
981 * Determine CPU clock frequency
982 */
983 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese87476ba2007-08-13 09:05:33 +0200984 if (primad_cpudv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100985 primad_cpudv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100986
Stefan Roese87476ba2007-08-13 09:05:33 +0200987 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
988 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100989
990 /*
991 * Determine PLB clock frequency
992 */
Stefan Roese87476ba2007-08-13 09:05:33 +0200993 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
994 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200995
996 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
997 sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200998
999 sysInfo->freqUART = sysInfo->freqVCOHz;
Stefan Roese17ffbc82007-03-21 13:38:59 +01001000}
1001
1002/********************************************
1003 * get_OPB_freq
1004 * return OPB bus freq in Hz
1005 *********************************************/
1006ulong get_OPB_freq (void)
1007{
1008 ulong val = 0;
1009
Stefan Roeseedd73f22007-10-21 08:12:41 +02001010 PPC4xx_SYS_INFO sys_info;
Stefan Roese17ffbc82007-03-21 13:38:59 +01001011
1012 get_sys_info (&sys_info);
1013 val = (CONFIG_SYS_CLK_FREQ * sys_info.pllFbkDiv) / sys_info.pllOpbDiv;
1014
1015 return val;
1016}
1017
Stefan Roese153b3e22007-10-05 17:10:59 +02001018#elif defined(CONFIG_405EX)
1019
1020/*
1021 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1022 * We need the specs!!!!
1023 */
1024static unsigned char get_fbdv(unsigned char index)
1025{
1026 unsigned char ret = 0;
1027 /* This is table should be 256 bytes.
1028 * Only take first 52 values.
1029 */
1030 unsigned char fbdv_tb[] = {
1031 0x00, 0xff, 0x7f, 0xfd,
1032 0x7a, 0xf5, 0x6a, 0xd5,
1033 0x2a, 0xd4, 0x29, 0xd3,
1034 0x26, 0xcc, 0x19, 0xb3,
1035 0x67, 0xce, 0x1d, 0xbb,
1036 0x77, 0xee, 0x5d, 0xba,
1037 0x74, 0xe9, 0x52, 0xa5,
1038 0x4b, 0x96, 0x2c, 0xd8,
1039 0x31, 0xe3, 0x46, 0x8d,
1040 0x1b, 0xb7, 0x6f, 0xde,
1041 0x3d, 0xfb, 0x76, 0xed,
1042 0x5a, 0xb5, 0x6b, 0xd6,
1043 0x2d, 0xdb, 0x36, 0xec,
1044
1045 };
1046
1047 if ((index & 0x7f) == 0)
1048 return 1;
1049 while (ret < sizeof (fbdv_tb)) {
1050 if (fbdv_tb[ret] == index)
1051 break;
1052 ret++;
1053 }
1054 ret++;
1055
1056 return ret;
1057}
1058
1059#define PLL_FBK_PLL_LOCAL 0
1060#define PLL_FBK_CPU 1
1061#define PLL_FBK_PERCLK 5
1062
1063void get_sys_info (sys_info_t * sysInfo)
1064{
1065 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1066 unsigned long m = 1;
1067 unsigned int tmp;
1068 unsigned char fwdva[16] = {
1069 1, 2, 14, 9, 4, 11, 16, 13,
1070 12, 5, 6, 15, 10, 7, 8, 3,
1071 };
1072 unsigned char sel, cpudv0, plb2xDiv;
1073
1074 mfcpr(cpr0_plld, tmp);
1075
1076 /*
1077 * Determine forward divider A
1078 */
1079 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1080
1081 /*
1082 * Determine FBK_DIV.
1083 */
1084 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1085
1086 /*
1087 * Determine PLBDV0
1088 */
1089 sysInfo->pllPlbDiv = 2;
1090
1091 /*
1092 * Determine PERDV0
1093 */
1094 mfcpr(cpr0_perd, tmp);
1095 tmp = (tmp >> 24) & 0x03;
1096 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1097
1098 /*
1099 * Determine OPBDV0
1100 */
1101 mfcpr(cpr0_opbd, tmp);
1102 tmp = (tmp >> 24) & 0x03;
1103 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1104
1105 /* Determine PLB2XDV0 */
1106 mfcpr(cpr0_plbd, tmp);
1107 tmp = (tmp >> 16) & 0x07;
1108 plb2xDiv = (tmp == 0) ? 8 : tmp;
1109
1110 /* Determine CPUDV0 */
1111 mfcpr(cpr0_cpud, tmp);
1112 tmp = (tmp >> 24) & 0x07;
1113 cpudv0 = (tmp == 0) ? 8 : tmp;
1114
1115 /* Determine SEL(5:7) in CPR0_PLLC */
1116 mfcpr(cpr0_pllc, tmp);
1117 sel = (tmp >> 24) & 0x07;
1118
1119 /*
1120 * Determine the M factor
1121 * PLL local: M = FBDV
1122 * CPU clock: M = FBDV * FWDVA * CPUDV0
1123 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1124 *
1125 */
1126 switch (sel) {
1127 case PLL_FBK_CPU:
1128 m = sysInfo->pllFwdDiv * cpudv0;
1129 break;
1130 case PLL_FBK_PERCLK:
1131 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1132 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1133 break;
Wolfgang Denka1be4762008-05-20 16:00:29 +02001134 case PLL_FBK_PLL_LOCAL:
Stefan Roese153b3e22007-10-05 17:10:59 +02001135 break;
1136 default:
1137 printf("%s unknown m\n", __FUNCTION__);
1138 return;
1139
1140 }
1141 m *= sysInfo->pllFbkDiv;
1142
1143 /*
1144 * Determine VCO clock frequency
1145 */
1146 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1147 (unsigned long long)sysClkPeriodPs;
1148
1149 /*
1150 * Determine CPU clock frequency
1151 */
1152 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1153
1154 /*
1155 * Determine PLB clock frequency, ddr1x should be the same
1156 */
1157 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1158 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1159 sysInfo->freqDDR = sysInfo->freqPLB;
1160 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +02001161 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roese153b3e22007-10-05 17:10:59 +02001162}
1163
1164/********************************************
1165 * get_OPB_freq
1166 * return OPB bus freq in Hz
1167 *********************************************/
1168ulong get_OPB_freq (void)
1169{
1170 ulong val = 0;
1171
Stefan Roeseedd73f22007-10-21 08:12:41 +02001172 PPC4xx_SYS_INFO sys_info;
Stefan Roese153b3e22007-10-05 17:10:59 +02001173
1174 get_sys_info (&sys_info);
1175 val = sys_info.freqPLB / sys_info.pllOpbDiv;
1176
1177 return val;
1178}
1179
wdenkc6097192002-11-03 00:24:07 +00001180#endif
1181
1182int get_clocks (void)
1183{
Stefan Roese17ffbc82007-03-21 13:38:59 +01001184#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1185 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roese153b3e22007-10-05 17:10:59 +02001186 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1187 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001188 sys_info_t sys_info;
1189
1190 get_sys_info (&sys_info);
1191 gd->cpu_clk = sys_info.freqProcessor;
1192 gd->bus_clk = sys_info.freqPLB;
1193
1194#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1195
1196#ifdef CONFIG_IOP480
wdenkc6097192002-11-03 00:24:07 +00001197 gd->cpu_clk = 66000000;
1198 gd->bus_clk = 66000000;
1199#endif
1200 return (0);
1201}
1202
1203
1204/********************************************
1205 * get_bus_freq
1206 * return PLB bus freq in Hz
1207 *********************************************/
1208ulong get_bus_freq (ulong dummy)
1209{
1210 ulong val;
1211
Stefan Roese17ffbc82007-03-21 13:38:59 +01001212#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1213 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roese153b3e22007-10-05 17:10:59 +02001214 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1215 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001216 sys_info_t sys_info;
1217
1218 get_sys_info (&sys_info);
1219 val = sys_info.freqPLB;
1220
1221#elif defined(CONFIG_IOP480)
1222
1223 val = 66;
1224
1225#else
1226# error get_bus_freq() not implemented
1227#endif
1228
1229 return val;
1230}