blob: 3e1a7016d94974149ba9e8c411e7ff53db35f8d7 [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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00006 */
7
8#include <common.h>
9#include <ppc_asm.tmpl>
Stefan Roeseb36df562010-09-09 19:18:00 +020010#include <asm/ppc4xx.h>
wdenkc6097192002-11-03 00:24:07 +000011#include <asm/processor.h>
12
Wolfgang Denkd87080b2006-03-31 18:32:53 +020013DECLARE_GLOBAL_DATA_PTR;
wdenkc6097192002-11-03 00:24:07 +000014
15#define ONE_BILLION 1000000000
Marian Balakowicz6c5879f2006-06-30 16:30:46 +020016#ifdef DEBUG
17#define DEBUGF(fmt,args...) printf(fmt ,##args)
18#else
19#define DEBUGF(fmt,args...)
20#endif
wdenkc6097192002-11-03 00:24:07 +000021
Matthias Fuchs3fb85882013-08-07 12:10:38 +020022#if defined(CONFIG_405GP)
wdenkc6097192002-11-03 00:24:07 +000023
Stefan Roese087dfdb2007-10-21 08:12:41 +020024void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
wdenkc6097192002-11-03 00:24:07 +000025{
26 unsigned long pllmr;
27 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
28 uint pvr = get_pvr();
29 unsigned long psr;
30 unsigned long m;
31
32 /*
33 * Read PLL Mode register
34 */
Stefan Roesed1c3b272009-09-09 16:25:29 +020035 pllmr = mfdcr (CPC0_PLLMR);
wdenkc6097192002-11-03 00:24:07 +000036
37 /*
38 * Read Pin Strapping register
39 */
Stefan Roesed1c3b272009-09-09 16:25:29 +020040 psr = mfdcr (CPC0_PSR);
wdenkc6097192002-11-03 00:24:07 +000041
42 /*
43 * Determine FWD_DIV.
44 */
45 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
46
47 /*
48 * Determine FBK_DIV.
49 */
50 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
51 if (sysInfo->pllFbkDiv == 0) {
52 sysInfo->pllFbkDiv = 16;
53 }
54
55 /*
56 * Determine PLB_DIV.
57 */
58 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
59
60 /*
61 * Determine PCI_DIV.
62 */
63 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
64
65 /*
66 * Determine EXTBUS_DIV.
67 */
68 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
69
70 /*
71 * Determine OPB_DIV.
72 */
73 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
74
75 /*
76 * Check if PPC405GPr used (mask minor revision field)
77 */
stroesebaa3d522003-04-04 16:00:33 +000078 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
wdenkc6097192002-11-03 00:24:07 +000079 /*
80 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
81 */
82 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
83
84 /*
85 * Determine factor m depending on PLL feedback clock source
86 */
87 if (!(psr & PSR_PCI_ASYNC_EN)) {
88 if (psr & PSR_NEW_MODE_EN) {
89 /*
90 * sync pci clock used as feedback (new mode)
91 */
92 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
93 } else {
94 /*
95 * sync pci clock used as feedback (legacy mode)
96 */
97 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
98 }
99 } else if (psr & PSR_NEW_MODE_EN) {
100 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
101 /*
102 * PerClk used as feedback (new mode)
103 */
104 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
105 } else {
106 /*
107 * CPU clock used as feedback (new mode)
108 */
109 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
110 }
111 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
112 /*
113 * PerClk used as feedback (legacy mode)
114 */
115 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
116 } else {
117 /*
118 * PLB clock used as feedback (legacy mode)
119 */
120 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
121 }
122
stroeseb39392a2004-12-16 18:13:53 +0000123 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
124 (unsigned long long)sysClkPeriodPs;
125 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
126 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
wdenkc6097192002-11-03 00:24:07 +0000127 } else {
128 /*
129 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
130 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
131 * to make sure it is within the proper range.
132 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
Wolfgang Denk8ed44d92008-10-19 02:35:50 +0200133 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
wdenkc6097192002-11-03 00:24:07 +0000134 */
135 if (sysInfo->pllFwdDiv == 1) {
136 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
137 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
138 } else {
stroeseb39392a2004-12-16 18:13:53 +0000139 sysInfo->freqVCOHz = ( 1000000000000LL *
140 (unsigned long long)sysInfo->pllFwdDiv *
141 (unsigned long long)sysInfo->pllFbkDiv *
142 (unsigned long long)sysInfo->pllPlbDiv
143 ) / (unsigned long long)sysClkPeriodPs;
144 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
145 sysInfo->pllFbkDiv)) * 10000;
146 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
wdenkc6097192002-11-03 00:24:07 +0000147 }
148 }
Stefan Roesefa8aea22007-10-22 07:33:52 +0200149
Stefan Roesee67af442009-09-14 11:13:34 +0200150 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
Matthias Fuchse1d09682008-04-18 17:24:32 +0200151 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200152 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000153}
154
155
156/********************************************
wdenkc6097192002-11-03 00:24:07 +0000157 * get_PCI_freq
158 * return PCI bus freq in Hz
159 *********************************************/
160ulong get_PCI_freq (void)
161{
162 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200163 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000164
165 get_sys_info (&sys_info);
166 val = sys_info.freqPLB / sys_info.pllPciDiv;
167 return val;
168}
169
170
171#elif defined(CONFIG_440)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200172
Feng Kan7d307932008-07-08 22:47:31 -0700173#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
Masahiro Yamada9ed32462014-09-29 01:37:59 +0900174 defined(CONFIG_460SX)
Stefan Roese2801b2d2008-03-11 15:05:50 +0100175static u8 pll_fwdv_multi_bits[] = {
176 /* values for: 1 - 16 */
177 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
178 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
179};
180
181u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
182{
183 u32 index;
184
185 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
186 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
187 return index + 1;
188
189 return 0;
190}
191
192static u8 pll_fbdv_multi_bits[] = {
193 /* values for: 1 - 100 */
194 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
195 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
196 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
197 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
198 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
199 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
200 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
201 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
202 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
203 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
204 /* values for: 101 - 200 */
205 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
206 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchellb9bbefc2008-05-07 09:00:23 -0700207 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roese2801b2d2008-03-11 15:05:50 +0100208 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
209 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
210 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
211 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
212 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
213 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
214 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
215 /* values for: 201 - 255 */
216 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
217 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
218 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
219 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
220 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
221 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
222};
223
224u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
225{
226 u32 index;
227
228 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
229 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
230 return index + 1;
231
232 return 0;
233}
234
235/*
236 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
237 * with latest EAS
238 */
239void get_sys_info (sys_info_t * sysInfo)
240{
241 unsigned long strp0;
242 unsigned long strp1;
243 unsigned long temp;
244 unsigned long m;
245 unsigned long plbedv0;
246
247 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200248 mfsdr(SDR0_SDSTP0, strp0);
249 mfsdr(SDR0_SDSTP1, strp1);
Stefan Roese2801b2d2008-03-11 15:05:50 +0100250
251 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
253
254 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
255 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
256
257 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
258 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
259
260 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
261 sysInfo->pllOpbDiv = temp ? temp : 4;
262
263 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
264 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
266
267 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
268 plbedv0 = temp ? temp: 8;
269
270 /* Calculate 'M' based on feedback source */
271 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
272 if (temp == 0) {
273 /* PLL internal feedback */
274 m = sysInfo->pllFbkDiv;
275 } else {
276 /* PLL PerClk feedback */
277 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
278 sysInfo->pllExtBusDiv;
279 }
280
281 /* Now calculate the individual clocks */
282 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
283 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
284 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
285 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
286 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
287 sysInfo->freqDDR = sysInfo->freqPLB;
288 sysInfo->freqUART = sysInfo->freqPLB;
289
290 return;
291}
292
293#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese887e2ec2006-09-07 11:51:23 +0200294 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roesec157d8e2005-08-01 16:41:48 +0200295void get_sys_info (sys_info_t *sysInfo)
296{
297 unsigned long temp;
298 unsigned long reg;
299 unsigned long lfdiv;
300 unsigned long m;
301 unsigned long prbdv0;
302 /*
303 WARNING: ASSUMES the following:
304 ENG=1
305 PRADV0=1
306 PRBDV0=1
307 */
308
309 /* Decode CPR0_PLLD0 for divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200310 mfcpr(CPR0_PLLD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200311 temp = (reg & PLLD_FWDVA_MASK) >> 16;
312 sysInfo->pllFwdDivA = temp ? temp : 16;
313 temp = (reg & PLLD_FWDVB_MASK) >> 8;
314 sysInfo->pllFwdDivB = temp ? temp: 8 ;
315 temp = (reg & PLLD_FBDV_MASK) >> 24;
316 sysInfo->pllFbkDiv = temp ? temp : 32;
317 lfdiv = reg & PLLD_LFBDV_MASK;
318
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200319 mfcpr(CPR0_OPBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200320 temp = (reg & OPBDDV_MASK) >> 24;
321 sysInfo->pllOpbDiv = temp ? temp : 4;
322
Stefan Roesed1c3b272009-09-09 16:25:29 +0200323 mfcpr(CPR0_PERD, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200324 temp = (reg & PERDV_MASK) >> 24;
325 sysInfo->pllExtBusDiv = temp ? temp : 8;
326
Niklaus Gigerddc922f2009-10-04 20:04:20 +0200327 mfcpr(CPR0_PRIMBD0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200328 temp = (reg & PRBDV_MASK) >> 24;
329 prbdv0 = temp ? temp : 8;
330
Stefan Roesed1c3b272009-09-09 16:25:29 +0200331 mfcpr(CPR0_SPCID, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200332 temp = (reg & SPCID_MASK) >> 24;
333 sysInfo->pllPciDiv = temp ? temp : 4;
334
335 /* Calculate 'M' based on feedback source */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200336 mfsdr(SDR0_SDSTP0, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200337 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
338 if (temp == 0) { /* PLL output */
339 /* Figure which pll to use */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200340 mfcpr(CPR0_PLLC, reg);
Stefan Roesec157d8e2005-08-01 16:41:48 +0200341 temp = (reg & PLLC_SRC_MASK) >> 29;
342 if (!temp) /* PLLOUTA */
343 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
344 else /* PLLOUTB */
345 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
346 }
347 else if (temp == 1) /* CPU output */
348 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
349 else /* PerClk */
350 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
351
352 /* Now calculate the individual clocks */
353 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
354 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
355 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
356 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200357 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200358 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200359 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200360
361 /* Figure which timer source to use */
Matthias Fuchs58ea1422009-07-22 17:27:56 +0200362 if (mfspr(SPRN_CCR1) & 0x0080) {
363 /* External Clock, assume same as SYS_CLK */
Stefan Roesec157d8e2005-08-01 16:41:48 +0200364 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
365 if (CONFIG_SYS_CLK_FREQ > temp)
366 sysInfo->freqTmrClk = temp;
367 else
368 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
369 }
370 else /* Internal clock */
371 sysInfo->freqTmrClk = sysInfo->freqProcessor;
372}
Stefan Roesefa8aea22007-10-22 07:33:52 +0200373
Stefan Roesec157d8e2005-08-01 16:41:48 +0200374/********************************************
375 * get_PCI_freq
376 * return PCI bus freq in Hz
377 *********************************************/
378ulong get_PCI_freq (void)
379{
380 sys_info_t sys_info;
381 get_sys_info (&sys_info);
382 return sys_info.freqPCI;
383}
384
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200385#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
386 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000387void get_sys_info (sys_info_t * sysInfo)
388{
389 unsigned long strp0;
390 unsigned long temp;
391 unsigned long m;
392
393 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200394 strp0 = mfdcr( CPC0_STRP0 );
wdenkc6097192002-11-03 00:24:07 +0000395 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
396 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
397 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
398 sysInfo->pllFbkDiv = temp ? temp : 16;
399 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
400 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
401
402 /* Calculate 'M' based on feedback source */
403 if( strp0 & PLLSYS0_EXTSL_MASK )
404 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
405 else
406 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
407
408 /* Now calculate the individual clocks */
409 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
410 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
411 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roesec157d8e2005-08-01 16:41:48 +0200412 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
413 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000414 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200415 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200416 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000417}
wdenkba56f622004-02-06 23:19:44 +0000418#else
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200419
420#if !defined(CONFIG_XILINX_440)
wdenkba56f622004-02-06 23:19:44 +0000421void get_sys_info (sys_info_t * sysInfo)
422{
423 unsigned long strp0;
424 unsigned long strp1;
425 unsigned long temp;
426 unsigned long temp1;
427 unsigned long lfdiv;
428 unsigned long m;
wdenk42dfe7a2004-03-14 22:25:36 +0000429 unsigned long prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000430
Stefan Roese4745aca2007-02-20 10:57:08 +0100431#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200432 unsigned long sys_freq;
433 unsigned long sys_per=0;
434 unsigned long msr;
435 unsigned long pci_clock_per;
436 unsigned long sdr_ddrpll;
437
438 /*-------------------------------------------------------------------------+
439 | Get the system clock period.
440 +-------------------------------------------------------------------------*/
441 sys_per = determine_sysper();
442
443 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
444
445 /*-------------------------------------------------------------------------+
446 | Calculate the system clock speed from the period.
447 +-------------------------------------------------------------------------*/
Stefan Roese4745aca2007-02-20 10:57:08 +0100448 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200449#endif
450
wdenkba56f622004-02-06 23:19:44 +0000451 /* Extract configured divisors */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200452 mfsdr( SDR0_SDSTP0,strp0 );
453 mfsdr( SDR0_SDSTP1,strp1 );
wdenkba56f622004-02-06 23:19:44 +0000454
455 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
456 sysInfo->pllFwdDivA = temp ? temp : 16 ;
457 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
458 sysInfo->pllFwdDivB = temp ? temp: 8 ;
459 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
460 sysInfo->pllFbkDiv = temp ? temp : 32;
461 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
462 sysInfo->pllOpbDiv = temp ? temp : 4;
463 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
464 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk0e6d7982004-03-14 00:07:33 +0000465 prbdv0 = (strp0 >> 2) & 0x7;
wdenkba56f622004-02-06 23:19:44 +0000466
467 /* Calculate 'M' based on feedback source */
468 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
469 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
470 lfdiv = temp1 ? temp1 : 64;
471 if (temp == 0) { /* PLL output */
472 /* Figure which pll to use */
473 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
474 if (!temp)
475 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
476 else
477 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
478 }
479 else if (temp == 1) /* CPU output */
480 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
481 else /* PerClk */
482 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
483
484 /* Now calculate the individual clocks */
Stefan Roese4745aca2007-02-20 10:57:08 +0100485#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200486 sysInfo->freqVCOMhz = (m * sys_freq) ;
487#else
Stefan Roese4745aca2007-02-20 10:57:08 +0100488 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200489#endif
wdenkba56f622004-02-06 23:19:44 +0000490 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk0e6d7982004-03-14 00:07:33 +0000491 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenkba56f622004-02-06 23:19:44 +0000492 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200493 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenkba56f622004-02-06 23:19:44 +0000494
Stefan Roese4745aca2007-02-20 10:57:08 +0100495#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200496 /* Determine PCI Clock Period */
497 pci_clock_per = determine_pci_clock_per();
498 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
Stefan Roesed1c3b272009-09-09 16:25:29 +0200499 mfsdr(SDR0_DDR0, sdr_ddrpll);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200500 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
501#endif
502
Stefan Roesefa8aea22007-10-22 07:33:52 +0200503 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200504}
505
506#endif
Ricardo Ribalda Delgadod865fd02008-07-17 11:44:12 +0200507#endif /* CONFIG_XILINX_440 */
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200508
Stefan Roese4745aca2007-02-20 10:57:08 +0100509#if defined(CONFIG_YUCCA)
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200510unsigned long determine_sysper(void)
511{
512 unsigned int fpga_clocking_reg;
513 unsigned int master_clock_selection;
514 unsigned long master_clock_per = 0;
515 unsigned long fb_div_selection;
516 unsigned int vco_div_reg_value;
517 unsigned long vco_div_selection;
518 unsigned long sys_per = 0;
519 int extClkVal;
520
521 /*-------------------------------------------------------------------------+
522 | Read FPGA reg 0 and reg 1 to get FPGA reg information
523 +-------------------------------------------------------------------------*/
524 fpga_clocking_reg = in16(FPGA_REG16);
525
526
527 /* Determine Master Clock Source Selection */
528 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
529
530 switch(master_clock_selection) {
531 case FPGA_REG16_MASTER_CLK_66_66:
532 master_clock_per = PERIOD_66_66MHZ;
533 break;
534 case FPGA_REG16_MASTER_CLK_50:
535 master_clock_per = PERIOD_50_00MHZ;
536 break;
537 case FPGA_REG16_MASTER_CLK_33_33:
538 master_clock_per = PERIOD_33_33MHZ;
539 break;
540 case FPGA_REG16_MASTER_CLK_25:
541 master_clock_per = PERIOD_25_00MHZ;
542 break;
543 case FPGA_REG16_MASTER_CLK_EXT:
544 if ((extClkVal==EXTCLK_33_33)
545 && (extClkVal==EXTCLK_50)
546 && (extClkVal==EXTCLK_66_66)
547 && (extClkVal==EXTCLK_83)) {
548 /* calculate master clock period from external clock value */
549 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
550 } else {
551 /* Unsupported */
552 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
553 hang();
554 }
555 break;
556 default:
557 /* Unsupported */
558 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
559 hang();
560 break;
561 }
562
563 /* Determine FB divisors values */
564 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
565 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
566 fb_div_selection = FPGA_FB_DIV_6;
567 else
568 fb_div_selection = FPGA_FB_DIV_12;
569 } else {
570 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
571 fb_div_selection = FPGA_FB_DIV_10;
572 else
573 fb_div_selection = FPGA_FB_DIV_20;
574 }
575
576 /* Determine VCO divisors values */
577 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
578
579 switch(vco_div_reg_value) {
580 case FPGA_REG16_VCO_DIV_4:
581 vco_div_selection = FPGA_VCO_DIV_4;
582 break;
583 case FPGA_REG16_VCO_DIV_6:
584 vco_div_selection = FPGA_VCO_DIV_6;
585 break;
586 case FPGA_REG16_VCO_DIV_8:
587 vco_div_selection = FPGA_VCO_DIV_8;
588 break;
589 case FPGA_REG16_VCO_DIV_10:
590 default:
591 vco_div_selection = FPGA_VCO_DIV_10;
592 break;
593 }
594
595 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
596 switch(master_clock_per) {
597 case PERIOD_25_00MHZ:
598 if (fb_div_selection == FPGA_FB_DIV_12) {
599 if (vco_div_selection == FPGA_VCO_DIV_4)
600 sys_per = PERIOD_75_00MHZ;
601 if (vco_div_selection == FPGA_VCO_DIV_6)
602 sys_per = PERIOD_50_00MHZ;
603 }
604 break;
605 case PERIOD_33_33MHZ:
606 if (fb_div_selection == FPGA_FB_DIV_6) {
607 if (vco_div_selection == FPGA_VCO_DIV_4)
608 sys_per = PERIOD_50_00MHZ;
609 if (vco_div_selection == FPGA_VCO_DIV_6)
610 sys_per = PERIOD_33_33MHZ;
611 }
612 if (fb_div_selection == FPGA_FB_DIV_10) {
613 if (vco_div_selection == FPGA_VCO_DIV_4)
614 sys_per = PERIOD_83_33MHZ;
615 if (vco_div_selection == FPGA_VCO_DIV_10)
616 sys_per = PERIOD_33_33MHZ;
617 }
618 if (fb_div_selection == FPGA_FB_DIV_12) {
619 if (vco_div_selection == FPGA_VCO_DIV_4)
620 sys_per = PERIOD_100_00MHZ;
621 if (vco_div_selection == FPGA_VCO_DIV_6)
622 sys_per = PERIOD_66_66MHZ;
623 if (vco_div_selection == FPGA_VCO_DIV_8)
624 sys_per = PERIOD_50_00MHZ;
625 }
626 break;
627 case PERIOD_50_00MHZ:
628 if (fb_div_selection == FPGA_FB_DIV_6) {
629 if (vco_div_selection == FPGA_VCO_DIV_4)
630 sys_per = PERIOD_75_00MHZ;
631 if (vco_div_selection == FPGA_VCO_DIV_6)
632 sys_per = PERIOD_50_00MHZ;
633 }
634 if (fb_div_selection == FPGA_FB_DIV_10) {
635 if (vco_div_selection == FPGA_VCO_DIV_6)
636 sys_per = PERIOD_83_33MHZ;
637 if (vco_div_selection == FPGA_VCO_DIV_10)
638 sys_per = PERIOD_50_00MHZ;
639 }
640 if (fb_div_selection == FPGA_FB_DIV_12) {
641 if (vco_div_selection == FPGA_VCO_DIV_6)
642 sys_per = PERIOD_100_00MHZ;
643 if (vco_div_selection == FPGA_VCO_DIV_8)
644 sys_per = PERIOD_75_00MHZ;
645 }
646 break;
647 case PERIOD_66_66MHZ:
648 if (fb_div_selection == FPGA_FB_DIV_6) {
649 if (vco_div_selection == FPGA_VCO_DIV_4)
650 sys_per = PERIOD_100_00MHZ;
651 if (vco_div_selection == FPGA_VCO_DIV_6)
652 sys_per = PERIOD_66_66MHZ;
653 if (vco_div_selection == FPGA_VCO_DIV_8)
654 sys_per = PERIOD_50_00MHZ;
655 }
656 if (fb_div_selection == FPGA_FB_DIV_10) {
657 if (vco_div_selection == FPGA_VCO_DIV_8)
658 sys_per = PERIOD_83_33MHZ;
659 if (vco_div_selection == FPGA_VCO_DIV_10)
660 sys_per = PERIOD_66_66MHZ;
661 }
662 if (fb_div_selection == FPGA_FB_DIV_12) {
663 if (vco_div_selection == FPGA_VCO_DIV_8)
664 sys_per = PERIOD_100_00MHZ;
665 }
666 break;
667 default:
668 break;
669 }
670
671 if (sys_per == 0) {
672 /* Other combinations are not supported */
673 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
674 hang();
675 }
676 } else {
677 /* calcul system clock without cheking */
678 /* if engineering option clock no check is selected */
679 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
680 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
681 }
682
683 return(sys_per);
Marian Balakowicz6c5879f2006-06-30 16:30:46 +0200684}
685
686/*-------------------------------------------------------------------------+
687| determine_pci_clock_per.
688+-------------------------------------------------------------------------*/
689unsigned long determine_pci_clock_per(void)
690{
691 unsigned long pci_clock_selection, pci_period;
692
693 /*-------------------------------------------------------------------------+
694 | Read FPGA reg 6 to get PCI 0 FPGA reg information
695 +-------------------------------------------------------------------------*/
696 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
697
698
699 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
700
701 switch (pci_clock_selection) {
702 case FPGA_REG16_PCI0_CLK_133_33:
703 pci_period = PERIOD_133_33MHZ;
704 break;
705 case FPGA_REG16_PCI0_CLK_100:
706 pci_period = PERIOD_100_00MHZ;
707 break;
708 case FPGA_REG16_PCI0_CLK_66_66:
709 pci_period = PERIOD_66_66MHZ;
710 break;
711 default:
712 pci_period = PERIOD_33_33MHZ;;
713 break;
714 }
715
716 return(pci_period);
wdenkba56f622004-02-06 23:19:44 +0000717}
718#endif
wdenkc6097192002-11-03 00:24:07 +0000719
Michal Simek9fea65a2008-06-24 09:54:09 +0200720#elif defined(CONFIG_XILINX_405)
wdenk028ab6b2004-02-23 23:54:43 +0000721extern void get_sys_info (sys_info_t * sysInfo);
722extern ulong get_PCI_freq (void);
723
wdenkc6097192002-11-03 00:24:07 +0000724#elif defined(CONFIG_405)
725
Stefan Roesefa8aea22007-10-22 07:33:52 +0200726void get_sys_info (sys_info_t * sysInfo)
727{
wdenkc6097192002-11-03 00:24:07 +0000728 sysInfo->freqVCOMhz=3125000;
729 sysInfo->freqProcessor=12*1000*1000;
730 sysInfo->freqPLB=50*1000*1000;
731 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000732}
733
stroeseb867d702003-05-23 11:18:02 +0000734#elif defined(CONFIG_405EP)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200735void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroeseb867d702003-05-23 11:18:02 +0000736{
737 unsigned long pllmr0;
738 unsigned long pllmr1;
739 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
740 unsigned long m;
741 unsigned long pllmr0_ccdv;
742
743 /*
744 * Read PLL Mode registers
745 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200746 pllmr0 = mfdcr (CPC0_PLLMR0);
747 pllmr1 = mfdcr (CPC0_PLLMR1);
stroeseb867d702003-05-23 11:18:02 +0000748
749 /*
750 * Determine forward divider A
751 */
752 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
753
754 /*
755 * Determine forward divider B (should be equal to A)
756 */
757 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
758
759 /*
760 * Determine FBK_DIV.
761 */
762 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200763 if (sysInfo->pllFbkDiv == 0)
stroeseb867d702003-05-23 11:18:02 +0000764 sysInfo->pllFbkDiv = 16;
stroeseb867d702003-05-23 11:18:02 +0000765
766 /*
767 * Determine PLB_DIV.
768 */
769 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
770
771 /*
772 * Determine PCI_DIV.
773 */
774 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
775
776 /*
777 * Determine EXTBUS_DIV.
778 */
779 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
780
781 /*
782 * Determine OPB_DIV.
783 */
784 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
785
786 /*
787 * Determine the M factor
788 */
789 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
790
791 /*
792 * Determine VCO clock frequency
793 */
stroeseb39392a2004-12-16 18:13:53 +0000794 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
795 (unsigned long long)sysClkPeriodPs;
stroeseb867d702003-05-23 11:18:02 +0000796
797 /*
798 * Determine CPU clock frequency
799 */
800 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
801 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenke55ca7e2004-07-01 21:40:08 +0000802 /*
803 * This is true if FWDVA == FWDVB:
804 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
805 * / pllmr0_ccdv;
806 */
807 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
808 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000809 } else {
810 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
811 }
812
813 /*
814 * Determine PLB clock frequency
815 */
816 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200817
818 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200819
Dirk Eibach9b1b8c82009-07-10 14:47:32 +0200820 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
821
Stefan Roesefa8aea22007-10-22 07:33:52 +0200822 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroeseb867d702003-05-23 11:18:02 +0000823}
824
825
826/********************************************
stroeseb867d702003-05-23 11:18:02 +0000827 * get_PCI_freq
828 * return PCI bus freq in Hz
829 *********************************************/
830ulong get_PCI_freq (void)
831{
832 ulong val;
Stefan Roese087dfdb2007-10-21 08:12:41 +0200833 PPC4xx_SYS_INFO sys_info;
stroeseb867d702003-05-23 11:18:02 +0000834
835 get_sys_info (&sys_info);
836 val = sys_info.freqPLB / sys_info.pllPciDiv;
837 return val;
838}
839
Stefan Roesee01bd212007-03-21 13:38:59 +0100840#elif defined(CONFIG_405EZ)
Stefan Roese087dfdb2007-10-21 08:12:41 +0200841void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roesee01bd212007-03-21 13:38:59 +0100842{
843 unsigned long cpr_plld;
Stefan Roese273db7e2007-08-13 09:05:33 +0200844 unsigned long cpr_pllc;
Stefan Roesee01bd212007-03-21 13:38:59 +0100845 unsigned long cpr_primad;
846 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
847 unsigned long primad_cpudv;
848 unsigned long m;
Stefan Roese95a4a592009-09-11 17:07:55 +0200849 unsigned long plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100850
851 /*
852 * Read PLL Mode registers
853 */
Stefan Roesed1c3b272009-09-09 16:25:29 +0200854 mfcpr(CPR0_PLLD, cpr_plld);
855 mfcpr(CPR0_PLLC, cpr_pllc);
Stefan Roesee01bd212007-03-21 13:38:59 +0100856
857 /*
858 * Determine forward divider A
859 */
860 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
861
862 /*
Stefan Roese273db7e2007-08-13 09:05:33 +0200863 * Determine forward divider B
Stefan Roesee01bd212007-03-21 13:38:59 +0100864 */
865 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200866 if (sysInfo->pllFwdDivB == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100867 sysInfo->pllFwdDivB = 8;
Stefan Roesee01bd212007-03-21 13:38:59 +0100868
869 /*
870 * Determine FBK_DIV.
871 */
872 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200873 if (sysInfo->pllFbkDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100874 sysInfo->pllFbkDiv = 256;
Stefan Roesee01bd212007-03-21 13:38:59 +0100875
876 /*
877 * Read CPR_PRIMAD register
878 */
Stefan Roeseafabb492010-09-12 06:21:37 +0200879 mfcpr(CPR0_PRIMAD, cpr_primad);
Stefan Roesefa8aea22007-10-22 07:33:52 +0200880
Stefan Roesee01bd212007-03-21 13:38:59 +0100881 /*
882 * Determine PLB_DIV.
883 */
884 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese273db7e2007-08-13 09:05:33 +0200885 if (sysInfo->pllPlbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100886 sysInfo->pllPlbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100887
888 /*
889 * Determine EXTBUS_DIV.
890 */
891 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese273db7e2007-08-13 09:05:33 +0200892 if (sysInfo->pllExtBusDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100893 sysInfo->pllExtBusDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100894
895 /*
896 * Determine OPB_DIV.
897 */
898 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese273db7e2007-08-13 09:05:33 +0200899 if (sysInfo->pllOpbDiv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100900 sysInfo->pllOpbDiv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100901
902 /*
903 * Determine the M factor
904 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200905 if (cpr_pllc & PLLC_SRC_MASK)
906 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
907 else
908 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100909
910 /*
911 * Determine VCO clock frequency
912 */
913 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
914 (unsigned long long)sysClkPeriodPs;
915
916 /*
917 * Determine CPU clock frequency
918 */
919 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese273db7e2007-08-13 09:05:33 +0200920 if (primad_cpudv == 0)
Stefan Roesee01bd212007-03-21 13:38:59 +0100921 primad_cpudv = 16;
Stefan Roesee01bd212007-03-21 13:38:59 +0100922
Stefan Roese273db7e2007-08-13 09:05:33 +0200923 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
924 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roesee01bd212007-03-21 13:38:59 +0100925
926 /*
927 * Determine PLB clock frequency
928 */
Stefan Roese273db7e2007-08-13 09:05:33 +0200929 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
930 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roesedbbd1252007-10-05 17:10:59 +0200931
Stefan Roesee67af442009-09-14 11:13:34 +0200932 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
933 sysInfo->pllOpbDiv;
934
Stefan Roesedbbd1252007-10-05 17:10:59 +0200935 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
936 sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +0200937
Stefan Roese95a4a592009-09-11 17:07:55 +0200938 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
939 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
940 sysInfo->pllFwdDivB);
941 sysInfo->freqUART = plloutb;
Stefan Roesee01bd212007-03-21 13:38:59 +0100942}
943
Stefan Roesedbbd1252007-10-05 17:10:59 +0200944#elif defined(CONFIG_405EX)
945
946/*
947 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
948 * We need the specs!!!!
949 */
950static unsigned char get_fbdv(unsigned char index)
951{
952 unsigned char ret = 0;
953 /* This is table should be 256 bytes.
954 * Only take first 52 values.
955 */
956 unsigned char fbdv_tb[] = {
957 0x00, 0xff, 0x7f, 0xfd,
958 0x7a, 0xf5, 0x6a, 0xd5,
959 0x2a, 0xd4, 0x29, 0xd3,
960 0x26, 0xcc, 0x19, 0xb3,
961 0x67, 0xce, 0x1d, 0xbb,
962 0x77, 0xee, 0x5d, 0xba,
963 0x74, 0xe9, 0x52, 0xa5,
964 0x4b, 0x96, 0x2c, 0xd8,
965 0x31, 0xe3, 0x46, 0x8d,
966 0x1b, 0xb7, 0x6f, 0xde,
967 0x3d, 0xfb, 0x76, 0xed,
968 0x5a, 0xb5, 0x6b, 0xd6,
969 0x2d, 0xdb, 0x36, 0xec,
970
971 };
972
973 if ((index & 0x7f) == 0)
974 return 1;
975 while (ret < sizeof (fbdv_tb)) {
976 if (fbdv_tb[ret] == index)
977 break;
978 ret++;
979 }
980 ret++;
981
982 return ret;
983}
984
985#define PLL_FBK_PLL_LOCAL 0
986#define PLL_FBK_CPU 1
987#define PLL_FBK_PERCLK 5
988
989void get_sys_info (sys_info_t * sysInfo)
990{
991 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
992 unsigned long m = 1;
993 unsigned int tmp;
994 unsigned char fwdva[16] = {
995 1, 2, 14, 9, 4, 11, 16, 13,
996 12, 5, 6, 15, 10, 7, 8, 3,
997 };
998 unsigned char sel, cpudv0, plb2xDiv;
999
Stefan Roesed1c3b272009-09-09 16:25:29 +02001000 mfcpr(CPR0_PLLD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001001
1002 /*
1003 * Determine forward divider A
1004 */
1005 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1006
1007 /*
1008 * Determine FBK_DIV.
1009 */
1010 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1011
1012 /*
1013 * Determine PLBDV0
1014 */
1015 sysInfo->pllPlbDiv = 2;
1016
1017 /*
1018 * Determine PERDV0
1019 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001020 mfcpr(CPR0_PERD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001021 tmp = (tmp >> 24) & 0x03;
1022 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1023
1024 /*
1025 * Determine OPBDV0
1026 */
Niklaus Gigerddc922f2009-10-04 20:04:20 +02001027 mfcpr(CPR0_OPBD0, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001028 tmp = (tmp >> 24) & 0x03;
1029 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1030
1031 /* Determine PLB2XDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001032 mfcpr(CPR0_PLBD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001033 tmp = (tmp >> 16) & 0x07;
1034 plb2xDiv = (tmp == 0) ? 8 : tmp;
1035
1036 /* Determine CPUDV0 */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001037 mfcpr(CPR0_CPUD, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001038 tmp = (tmp >> 24) & 0x07;
1039 cpudv0 = (tmp == 0) ? 8 : tmp;
1040
1041 /* Determine SEL(5:7) in CPR0_PLLC */
Stefan Roesed1c3b272009-09-09 16:25:29 +02001042 mfcpr(CPR0_PLLC, tmp);
Stefan Roesedbbd1252007-10-05 17:10:59 +02001043 sel = (tmp >> 24) & 0x07;
1044
1045 /*
1046 * Determine the M factor
1047 * PLL local: M = FBDV
1048 * CPU clock: M = FBDV * FWDVA * CPUDV0
1049 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1050 *
1051 */
1052 switch (sel) {
1053 case PLL_FBK_CPU:
1054 m = sysInfo->pllFwdDiv * cpudv0;
1055 break;
1056 case PLL_FBK_PERCLK:
1057 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1058 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1059 break;
Wolfgang Denk53677ef2008-05-20 16:00:29 +02001060 case PLL_FBK_PLL_LOCAL:
Stefan Roesedbbd1252007-10-05 17:10:59 +02001061 break;
1062 default:
1063 printf("%s unknown m\n", __FUNCTION__);
1064 return;
1065
1066 }
1067 m *= sysInfo->pllFbkDiv;
1068
1069 /*
1070 * Determine VCO clock frequency
1071 */
1072 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1073 (unsigned long long)sysClkPeriodPs;
1074
1075 /*
1076 * Determine CPU clock frequency
1077 */
1078 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1079
1080 /*
1081 * Determine PLB clock frequency, ddr1x should be the same
1082 */
1083 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1084 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1085 sysInfo->freqDDR = sysInfo->freqPLB;
1086 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roesefa8aea22007-10-22 07:33:52 +02001087 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roesedbbd1252007-10-05 17:10:59 +02001088}
1089
wdenkc6097192002-11-03 00:24:07 +00001090#endif
1091
1092int get_clocks (void)
1093{
wdenkc6097192002-11-03 00:24:07 +00001094 sys_info_t sys_info;
1095
1096 get_sys_info (&sys_info);
1097 gd->cpu_clk = sys_info.freqProcessor;
1098 gd->bus_clk = sys_info.freqPLB;
1099
wdenkc6097192002-11-03 00:24:07 +00001100 return (0);
1101}
1102
1103
1104/********************************************
1105 * get_bus_freq
1106 * return PLB bus freq in Hz
1107 *********************************************/
1108ulong get_bus_freq (ulong dummy)
1109{
1110 ulong val;
1111
Matthias Fuchs3fb85882013-08-07 12:10:38 +02001112#if defined(CONFIG_405GP) || \
Stefan Roesee01bd212007-03-21 13:38:59 +01001113 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roesedbbd1252007-10-05 17:10:59 +02001114 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1115 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001116 sys_info_t sys_info;
1117
1118 get_sys_info (&sys_info);
1119 val = sys_info.freqPLB;
wdenkc6097192002-11-03 00:24:07 +00001120#else
1121# error get_bus_freq() not implemented
1122#endif
1123
1124 return val;
1125}
Stefan Roesee67af442009-09-14 11:13:34 +02001126
Stefan Roesee67af442009-09-14 11:13:34 +02001127ulong get_OPB_freq (void)
1128{
1129 PPC4xx_SYS_INFO sys_info;
1130
1131 get_sys_info (&sys_info);
1132
1133 return sys_info.freqOPB;
1134}