blob: 7e077d5a9f28a5216219d79ab6adfc0dd5e69466 [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 *
Wolfgang Denkd79de1d2013-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 Roese247e9d72010-09-09 19:18:00 +020010#include <asm/ppc4xx.h>
wdenkc6097192002-11-03 00:24:07 +000011#include <asm/processor.h>
12
Wolfgang Denk6405a152006-03-31 18:32:53 +020013DECLARE_GLOBAL_DATA_PTR;
wdenkc6097192002-11-03 00:24:07 +000014
15#define ONE_BILLION 1000000000
Marian Balakowicz49d0eee2006-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
Stefan Roesecc019d12008-03-11 15:05:50 +010022#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
23
Matthias Fuchse54a67f2013-08-07 12:10:38 +020024#if defined(CONFIG_405GP)
wdenkc6097192002-11-03 00:24:07 +000025
Stefan Roeseedd73f22007-10-21 08:12:41 +020026void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
wdenkc6097192002-11-03 00:24:07 +000027{
28 unsigned long pllmr;
29 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
30 uint pvr = get_pvr();
31 unsigned long psr;
32 unsigned long m;
33
34 /*
35 * Read PLL Mode register
36 */
Stefan Roese918010a2009-09-09 16:25:29 +020037 pllmr = mfdcr (CPC0_PLLMR);
wdenkc6097192002-11-03 00:24:07 +000038
39 /*
40 * Read Pin Strapping register
41 */
Stefan Roese918010a2009-09-09 16:25:29 +020042 psr = mfdcr (CPC0_PSR);
wdenkc6097192002-11-03 00:24:07 +000043
44 /*
45 * Determine FWD_DIV.
46 */
47 sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29);
48
49 /*
50 * Determine FBK_DIV.
51 */
52 sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25);
53 if (sysInfo->pllFbkDiv == 0) {
54 sysInfo->pllFbkDiv = 16;
55 }
56
57 /*
58 * Determine PLB_DIV.
59 */
60 sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1;
61
62 /*
63 * Determine PCI_DIV.
64 */
65 sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1;
66
67 /*
68 * Determine EXTBUS_DIV.
69 */
70 sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2;
71
72 /*
73 * Determine OPB_DIV.
74 */
75 sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1;
76
77 /*
78 * Check if PPC405GPr used (mask minor revision field)
79 */
stroeseff90f802003-04-04 16:00:33 +000080 if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
wdenkc6097192002-11-03 00:24:07 +000081 /*
82 * Determine FWD_DIV B (only PPC405GPr with new mode strapping).
83 */
84 sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK);
85
86 /*
87 * Determine factor m depending on PLL feedback clock source
88 */
89 if (!(psr & PSR_PCI_ASYNC_EN)) {
90 if (psr & PSR_NEW_MODE_EN) {
91 /*
92 * sync pci clock used as feedback (new mode)
93 */
94 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv;
95 } else {
96 /*
97 * sync pci clock used as feedback (legacy mode)
98 */
99 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv;
100 }
101 } else if (psr & PSR_NEW_MODE_EN) {
102 if (psr & PSR_PERCLK_SYNC_MODE_EN) {
103 /*
104 * PerClk used as feedback (new mode)
105 */
106 m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv;
107 } else {
108 /*
109 * CPU clock used as feedback (new mode)
110 */
111 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
112 }
113 } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) {
114 /*
115 * PerClk used as feedback (legacy mode)
116 */
117 m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv;
118 } else {
119 /*
120 * PLB clock used as feedback (legacy mode)
121 */
122 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv;
123 }
124
stroese5d542f12004-12-16 18:13:53 +0000125 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
126 (unsigned long long)sysClkPeriodPs;
127 sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv;
128 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv);
wdenkc6097192002-11-03 00:24:07 +0000129 } else {
130 /*
131 * Check pllFwdDiv to see if running in bypass mode where the CPU speed
132 * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO
133 * to make sure it is within the proper range.
134 * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV
Wolfgang Denkaf0501a2008-10-19 02:35:50 +0200135 * Note freqVCO is calculated in MHz to avoid errors introduced by rounding.
wdenkc6097192002-11-03 00:24:07 +0000136 */
137 if (sysInfo->pllFwdDiv == 1) {
138 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ;
139 sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv;
140 } else {
stroese5d542f12004-12-16 18:13:53 +0000141 sysInfo->freqVCOHz = ( 1000000000000LL *
142 (unsigned long long)sysInfo->pllFwdDiv *
143 (unsigned long long)sysInfo->pllFbkDiv *
144 (unsigned long long)sysInfo->pllPlbDiv
145 ) / (unsigned long long)sysClkPeriodPs;
146 sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) /
147 sysInfo->pllFbkDiv)) * 10000;
148 sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv;
wdenkc6097192002-11-03 00:24:07 +0000149 }
150 }
Stefan Roese628d3922007-10-22 07:33:52 +0200151
Stefan Roese11f51692009-09-14 11:13:34 +0200152 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
Matthias Fuchs3c70edc2008-04-18 17:24:32 +0200153 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200154 sysInfo->freqUART = sysInfo->freqProcessor;
wdenkc6097192002-11-03 00:24:07 +0000155}
156
157
158/********************************************
wdenkc6097192002-11-03 00:24:07 +0000159 * get_PCI_freq
160 * return PCI bus freq in Hz
161 *********************************************/
162ulong get_PCI_freq (void)
163{
164 ulong val;
Stefan Roeseedd73f22007-10-21 08:12:41 +0200165 PPC4xx_SYS_INFO sys_info;
wdenkc6097192002-11-03 00:24:07 +0000166
167 get_sys_info (&sys_info);
168 val = sys_info.freqPLB / sys_info.pllPciDiv;
169 return val;
170}
171
172
173#elif defined(CONFIG_440)
Stefan Roese326c9712005-08-01 16:41:48 +0200174
Feng Kan224bc962008-07-08 22:47:31 -0700175#if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
Tirumala Marri95ac4282010-09-28 14:15:14 -0700176 defined(CONFIG_460SX) || defined(CONFIG_APM821XX)
Stefan Roesecc019d12008-03-11 15:05:50 +0100177static u8 pll_fwdv_multi_bits[] = {
178 /* values for: 1 - 16 */
179 0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
180 0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
181};
182
183u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
184{
185 u32 index;
186
187 for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
188 if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
189 return index + 1;
190
191 return 0;
192}
193
194static u8 pll_fbdv_multi_bits[] = {
195 /* values for: 1 - 100 */
196 0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
197 0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
198 0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
199 0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
200 0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
201 0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
202 0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
203 0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
204 0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
205 0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
206 /* values for: 101 - 200 */
207 0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
208 0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
Dave Mitchell05e89742008-05-07 09:00:23 -0700209 0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
Stefan Roesecc019d12008-03-11 15:05:50 +0100210 0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
211 0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
212 0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
213 0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
214 0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
215 0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
216 0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
217 /* values for: 201 - 255 */
218 0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
219 0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
220 0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
221 0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
222 0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
223 0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
224};
225
226u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
227{
228 u32 index;
229
230 for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
231 if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
232 return index + 1;
233
234 return 0;
235}
236
Tirumala Marri95ac4282010-09-28 14:15:14 -0700237#if defined(CONFIG_APM821XX)
238
239void get_sys_info(sys_info_t *sysInfo)
240{
241 unsigned long plld;
242 unsigned long temp;
243 unsigned long mul;
244 unsigned long cpudv;
245 unsigned long plb2dv;
246 unsigned long ddr2dv;
247
248 /* Calculate Forward divisor A and Feeback divisor */
249 mfcpr(CPR0_PLLD, plld);
250
251 temp = CPR0_PLLD_FWDVA(plld);
252 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
253
254 temp = CPR0_PLLD_FDV(plld);
255 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
256
257 /* Calculate OPB clock divisor */
258 mfcpr(CPR0_OPBD, temp);
259 temp = CPR0_OPBD_OPBDV(temp);
260 sysInfo->pllOpbDiv = temp ? temp : 4;
261
262 /* Calculate Peripheral clock divisor */
263 mfcpr(CPR0_PERD, temp);
264 temp = CPR0_PERD_PERDV(temp);
265 sysInfo->pllExtBusDiv = temp ? temp : 4;
266
267 /* Calculate CPU clock divisor */
268 mfcpr(CPR0_CPUD, temp);
269 temp = CPR0_CPUD_CPUDV(temp);
270 cpudv = temp ? temp : 8;
271
272 /* Calculate PLB2 clock divisor */
273 mfcpr(CPR0_PLB2D, temp);
274 temp = CPR0_PLB2D_PLB2DV(temp);
275 plb2dv = temp ? temp : 4;
276
277 /* Calculate DDR2 clock divisor */
278 mfcpr(CPR0_DDR2D, temp);
279 temp = CPR0_DDR2D_DDR2DV(temp);
280 ddr2dv = temp ? temp : 4;
281
282 /* Calculate 'M' based on feedback source */
283 mfcpr(CPR0_PLLC, temp);
284 temp = CPR0_PLLC_SEL(temp);
285 if (temp == 0) {
286 /* PLL internal feedback */
287 mul = sysInfo->pllFbkDiv;
288 } else {
289 /* PLL PerClk feedback */
290 mul = sysInfo->pllFwdDivA * sysInfo->pllFbkDiv * cpudv
291 * plb2dv * 2 * sysInfo->pllOpbDiv *
292 sysInfo->pllExtBusDiv;
293 }
294
295 /* Now calculate the individual clocks */
296 sysInfo->freqVCOMhz = (mul * CONFIG_SYS_CLK_FREQ) + (mul >> 1);
297 sysInfo->freqProcessor = sysInfo->freqVCOMhz /
298 sysInfo->pllFwdDivA / cpudv;
299 sysInfo->freqPLB = sysInfo->freqVCOMhz /
300 sysInfo->pllFwdDivA / cpudv / plb2dv / 2;
301 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
302 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
303 sysInfo->freqDDR = sysInfo->freqVCOMhz /
304 sysInfo->pllFwdDivA / cpudv / ddr2dv / 2;
305 sysInfo->freqUART = sysInfo->freqPLB;
306}
307
308#else
Stefan Roesecc019d12008-03-11 15:05:50 +0100309/*
310 * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
311 * with latest EAS
312 */
313void get_sys_info (sys_info_t * sysInfo)
314{
315 unsigned long strp0;
316 unsigned long strp1;
317 unsigned long temp;
318 unsigned long m;
319 unsigned long plbedv0;
320
321 /* Extract configured divisors */
Stefan Roese918010a2009-09-09 16:25:29 +0200322 mfsdr(SDR0_SDSTP0, strp0);
323 mfsdr(SDR0_SDSTP1, strp1);
Stefan Roesecc019d12008-03-11 15:05:50 +0100324
325 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
326 sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
327
328 temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
329 sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
330
331 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
332 sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
333
334 temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
335 sysInfo->pllOpbDiv = temp ? temp : 4;
336
337 /* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
338 temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
339 sysInfo->pllExtBusDiv = temp ? temp : 4;
340
341 temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
342 plbedv0 = temp ? temp: 8;
343
344 /* Calculate 'M' based on feedback source */
345 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
346 if (temp == 0) {
347 /* PLL internal feedback */
348 m = sysInfo->pllFbkDiv;
349 } else {
350 /* PLL PerClk feedback */
351 m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
352 sysInfo->pllExtBusDiv;
353 }
354
355 /* Now calculate the individual clocks */
356 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
357 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
358 sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
359 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
360 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
361 sysInfo->freqDDR = sysInfo->freqPLB;
362 sysInfo->freqUART = sysInfo->freqPLB;
363
364 return;
365}
Tirumala Marri95ac4282010-09-28 14:15:14 -0700366#endif
Stefan Roesecc019d12008-03-11 15:05:50 +0100367
368#elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
Stefan Roese42fbddd2006-09-07 11:51:23 +0200369 defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
Stefan Roese326c9712005-08-01 16:41:48 +0200370void get_sys_info (sys_info_t *sysInfo)
371{
372 unsigned long temp;
373 unsigned long reg;
374 unsigned long lfdiv;
375 unsigned long m;
376 unsigned long prbdv0;
377 /*
378 WARNING: ASSUMES the following:
379 ENG=1
380 PRADV0=1
381 PRBDV0=1
382 */
383
384 /* Decode CPR0_PLLD0 for divisors */
Stefan Roese918010a2009-09-09 16:25:29 +0200385 mfcpr(CPR0_PLLD, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200386 temp = (reg & PLLD_FWDVA_MASK) >> 16;
387 sysInfo->pllFwdDivA = temp ? temp : 16;
388 temp = (reg & PLLD_FWDVB_MASK) >> 8;
389 sysInfo->pllFwdDivB = temp ? temp: 8 ;
390 temp = (reg & PLLD_FBDV_MASK) >> 24;
391 sysInfo->pllFbkDiv = temp ? temp : 32;
392 lfdiv = reg & PLLD_LFBDV_MASK;
393
Niklaus Giger728bd0a2009-10-04 20:04:20 +0200394 mfcpr(CPR0_OPBD0, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200395 temp = (reg & OPBDDV_MASK) >> 24;
396 sysInfo->pllOpbDiv = temp ? temp : 4;
397
Stefan Roese918010a2009-09-09 16:25:29 +0200398 mfcpr(CPR0_PERD, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200399 temp = (reg & PERDV_MASK) >> 24;
400 sysInfo->pllExtBusDiv = temp ? temp : 8;
401
Niklaus Giger728bd0a2009-10-04 20:04:20 +0200402 mfcpr(CPR0_PRIMBD0, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200403 temp = (reg & PRBDV_MASK) >> 24;
404 prbdv0 = temp ? temp : 8;
405
Stefan Roese918010a2009-09-09 16:25:29 +0200406 mfcpr(CPR0_SPCID, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200407 temp = (reg & SPCID_MASK) >> 24;
408 sysInfo->pllPciDiv = temp ? temp : 4;
409
410 /* Calculate 'M' based on feedback source */
Stefan Roese918010a2009-09-09 16:25:29 +0200411 mfsdr(SDR0_SDSTP0, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200412 temp = (reg & PLLSYS0_SEL_MASK) >> 27;
413 if (temp == 0) { /* PLL output */
414 /* Figure which pll to use */
Stefan Roese918010a2009-09-09 16:25:29 +0200415 mfcpr(CPR0_PLLC, reg);
Stefan Roese326c9712005-08-01 16:41:48 +0200416 temp = (reg & PLLC_SRC_MASK) >> 29;
417 if (!temp) /* PLLOUTA */
418 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
419 else /* PLLOUTB */
420 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
421 }
422 else if (temp == 1) /* CPU output */
423 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
424 else /* PerClk */
425 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
426
427 /* Now calculate the individual clocks */
428 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
429 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
430 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
431 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200432 sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
Stefan Roese326c9712005-08-01 16:41:48 +0200433 sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200434 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roese326c9712005-08-01 16:41:48 +0200435
436 /* Figure which timer source to use */
Matthias Fuchs730b2d22009-07-22 17:27:56 +0200437 if (mfspr(SPRN_CCR1) & 0x0080) {
438 /* External Clock, assume same as SYS_CLK */
Stefan Roese326c9712005-08-01 16:41:48 +0200439 temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */
440 if (CONFIG_SYS_CLK_FREQ > temp)
441 sysInfo->freqTmrClk = temp;
442 else
443 sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
444 }
445 else /* Internal clock */
446 sysInfo->freqTmrClk = sysInfo->freqProcessor;
447}
Stefan Roese628d3922007-10-22 07:33:52 +0200448
Stefan Roese326c9712005-08-01 16:41:48 +0200449/********************************************
450 * get_PCI_freq
451 * return PCI bus freq in Hz
452 *********************************************/
453ulong get_PCI_freq (void)
454{
455 sys_info_t sys_info;
456 get_sys_info (&sys_info);
457 return sys_info.freqPCI;
458}
459
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200460#elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
461 && !defined(CONFIG_XILINX_440)
wdenkc6097192002-11-03 00:24:07 +0000462void get_sys_info (sys_info_t * sysInfo)
463{
464 unsigned long strp0;
465 unsigned long temp;
466 unsigned long m;
467
468 /* Extract configured divisors */
Stefan Roese918010a2009-09-09 16:25:29 +0200469 strp0 = mfdcr( CPC0_STRP0 );
wdenkc6097192002-11-03 00:24:07 +0000470 sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
471 sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
472 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
473 sysInfo->pllFbkDiv = temp ? temp : 16;
474 sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
475 sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
476
477 /* Calculate 'M' based on feedback source */
478 if( strp0 & PLLSYS0_EXTSL_MASK )
479 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
480 else
481 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
482
483 /* Now calculate the individual clocks */
484 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
485 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
486 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
Stefan Roese326c9712005-08-01 16:41:48 +0200487 if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
488 sysInfo->freqPLB >>= 1;
wdenkc6097192002-11-03 00:24:07 +0000489 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200490 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200491 sysInfo->freqUART = sysInfo->freqPLB;
wdenkc6097192002-11-03 00:24:07 +0000492}
wdenk544e9732004-02-06 23:19:44 +0000493#else
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200494
495#if !defined(CONFIG_XILINX_440)
wdenk544e9732004-02-06 23:19:44 +0000496void get_sys_info (sys_info_t * sysInfo)
497{
498 unsigned long strp0;
499 unsigned long strp1;
500 unsigned long temp;
501 unsigned long temp1;
502 unsigned long lfdiv;
503 unsigned long m;
wdenkc35ba4e2004-03-14 22:25:36 +0000504 unsigned long prbdv0;
wdenk544e9732004-02-06 23:19:44 +0000505
Stefan Roesea8856e32007-02-20 10:57:08 +0100506#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200507 unsigned long sys_freq;
508 unsigned long sys_per=0;
509 unsigned long msr;
510 unsigned long pci_clock_per;
511 unsigned long sdr_ddrpll;
512
513 /*-------------------------------------------------------------------------+
514 | Get the system clock period.
515 +-------------------------------------------------------------------------*/
516 sys_per = determine_sysper();
517
518 msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */
519
520 /*-------------------------------------------------------------------------+
521 | Calculate the system clock speed from the period.
522 +-------------------------------------------------------------------------*/
Stefan Roesea8856e32007-02-20 10:57:08 +0100523 sys_freq = (ONE_BILLION / sys_per) * 1000;
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200524#endif
525
wdenk544e9732004-02-06 23:19:44 +0000526 /* Extract configured divisors */
Stefan Roese918010a2009-09-09 16:25:29 +0200527 mfsdr( SDR0_SDSTP0,strp0 );
528 mfsdr( SDR0_SDSTP1,strp1 );
wdenk544e9732004-02-06 23:19:44 +0000529
530 temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
531 sysInfo->pllFwdDivA = temp ? temp : 16 ;
532 temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
533 sysInfo->pllFwdDivB = temp ? temp: 8 ;
534 temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
535 sysInfo->pllFbkDiv = temp ? temp : 32;
536 temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
537 sysInfo->pllOpbDiv = temp ? temp : 4;
538 temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
539 sysInfo->pllExtBusDiv = temp ? temp : 4;
wdenk00fe1612004-03-14 00:07:33 +0000540 prbdv0 = (strp0 >> 2) & 0x7;
wdenk544e9732004-02-06 23:19:44 +0000541
542 /* Calculate 'M' based on feedback source */
543 temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
544 temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
545 lfdiv = temp1 ? temp1 : 64;
546 if (temp == 0) { /* PLL output */
547 /* Figure which pll to use */
548 temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
549 if (!temp)
550 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
551 else
552 m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
553 }
554 else if (temp == 1) /* CPU output */
555 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
556 else /* PerClk */
557 m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
558
559 /* Now calculate the individual clocks */
Stefan Roesea8856e32007-02-20 10:57:08 +0100560#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200561 sysInfo->freqVCOMhz = (m * sys_freq) ;
562#else
Stefan Roesea8856e32007-02-20 10:57:08 +0100563 sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200564#endif
wdenk544e9732004-02-06 23:19:44 +0000565 sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
wdenk00fe1612004-03-14 00:07:33 +0000566 sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
wdenk544e9732004-02-06 23:19:44 +0000567 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200568 sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
wdenk544e9732004-02-06 23:19:44 +0000569
Stefan Roesea8856e32007-02-20 10:57:08 +0100570#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200571 /* Determine PCI Clock Period */
572 pci_clock_per = determine_pci_clock_per();
573 sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
Stefan Roese918010a2009-09-09 16:25:29 +0200574 mfsdr(SDR0_DDR0, sdr_ddrpll);
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200575 sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
576#endif
577
Stefan Roese628d3922007-10-22 07:33:52 +0200578 sysInfo->freqUART = sysInfo->freqPLB;
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200579}
580
581#endif
Ricardo Ribalda Delgado95c50202008-07-17 11:44:12 +0200582#endif /* CONFIG_XILINX_440 */
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200583
Stefan Roesea8856e32007-02-20 10:57:08 +0100584#if defined(CONFIG_YUCCA)
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200585unsigned long determine_sysper(void)
586{
587 unsigned int fpga_clocking_reg;
588 unsigned int master_clock_selection;
589 unsigned long master_clock_per = 0;
590 unsigned long fb_div_selection;
591 unsigned int vco_div_reg_value;
592 unsigned long vco_div_selection;
593 unsigned long sys_per = 0;
594 int extClkVal;
595
596 /*-------------------------------------------------------------------------+
597 | Read FPGA reg 0 and reg 1 to get FPGA reg information
598 +-------------------------------------------------------------------------*/
599 fpga_clocking_reg = in16(FPGA_REG16);
600
601
602 /* Determine Master Clock Source Selection */
603 master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
604
605 switch(master_clock_selection) {
606 case FPGA_REG16_MASTER_CLK_66_66:
607 master_clock_per = PERIOD_66_66MHZ;
608 break;
609 case FPGA_REG16_MASTER_CLK_50:
610 master_clock_per = PERIOD_50_00MHZ;
611 break;
612 case FPGA_REG16_MASTER_CLK_33_33:
613 master_clock_per = PERIOD_33_33MHZ;
614 break;
615 case FPGA_REG16_MASTER_CLK_25:
616 master_clock_per = PERIOD_25_00MHZ;
617 break;
618 case FPGA_REG16_MASTER_CLK_EXT:
619 if ((extClkVal==EXTCLK_33_33)
620 && (extClkVal==EXTCLK_50)
621 && (extClkVal==EXTCLK_66_66)
622 && (extClkVal==EXTCLK_83)) {
623 /* calculate master clock period from external clock value */
624 master_clock_per=(ONE_BILLION/extClkVal) * 1000;
625 } else {
626 /* Unsupported */
627 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
628 hang();
629 }
630 break;
631 default:
632 /* Unsupported */
633 DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
634 hang();
635 break;
636 }
637
638 /* Determine FB divisors values */
639 if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
640 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
641 fb_div_selection = FPGA_FB_DIV_6;
642 else
643 fb_div_selection = FPGA_FB_DIV_12;
644 } else {
645 if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
646 fb_div_selection = FPGA_FB_DIV_10;
647 else
648 fb_div_selection = FPGA_FB_DIV_20;
649 }
650
651 /* Determine VCO divisors values */
652 vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
653
654 switch(vco_div_reg_value) {
655 case FPGA_REG16_VCO_DIV_4:
656 vco_div_selection = FPGA_VCO_DIV_4;
657 break;
658 case FPGA_REG16_VCO_DIV_6:
659 vco_div_selection = FPGA_VCO_DIV_6;
660 break;
661 case FPGA_REG16_VCO_DIV_8:
662 vco_div_selection = FPGA_VCO_DIV_8;
663 break;
664 case FPGA_REG16_VCO_DIV_10:
665 default:
666 vco_div_selection = FPGA_VCO_DIV_10;
667 break;
668 }
669
670 if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
671 switch(master_clock_per) {
672 case PERIOD_25_00MHZ:
673 if (fb_div_selection == FPGA_FB_DIV_12) {
674 if (vco_div_selection == FPGA_VCO_DIV_4)
675 sys_per = PERIOD_75_00MHZ;
676 if (vco_div_selection == FPGA_VCO_DIV_6)
677 sys_per = PERIOD_50_00MHZ;
678 }
679 break;
680 case PERIOD_33_33MHZ:
681 if (fb_div_selection == FPGA_FB_DIV_6) {
682 if (vco_div_selection == FPGA_VCO_DIV_4)
683 sys_per = PERIOD_50_00MHZ;
684 if (vco_div_selection == FPGA_VCO_DIV_6)
685 sys_per = PERIOD_33_33MHZ;
686 }
687 if (fb_div_selection == FPGA_FB_DIV_10) {
688 if (vco_div_selection == FPGA_VCO_DIV_4)
689 sys_per = PERIOD_83_33MHZ;
690 if (vco_div_selection == FPGA_VCO_DIV_10)
691 sys_per = PERIOD_33_33MHZ;
692 }
693 if (fb_div_selection == FPGA_FB_DIV_12) {
694 if (vco_div_selection == FPGA_VCO_DIV_4)
695 sys_per = PERIOD_100_00MHZ;
696 if (vco_div_selection == FPGA_VCO_DIV_6)
697 sys_per = PERIOD_66_66MHZ;
698 if (vco_div_selection == FPGA_VCO_DIV_8)
699 sys_per = PERIOD_50_00MHZ;
700 }
701 break;
702 case PERIOD_50_00MHZ:
703 if (fb_div_selection == FPGA_FB_DIV_6) {
704 if (vco_div_selection == FPGA_VCO_DIV_4)
705 sys_per = PERIOD_75_00MHZ;
706 if (vco_div_selection == FPGA_VCO_DIV_6)
707 sys_per = PERIOD_50_00MHZ;
708 }
709 if (fb_div_selection == FPGA_FB_DIV_10) {
710 if (vco_div_selection == FPGA_VCO_DIV_6)
711 sys_per = PERIOD_83_33MHZ;
712 if (vco_div_selection == FPGA_VCO_DIV_10)
713 sys_per = PERIOD_50_00MHZ;
714 }
715 if (fb_div_selection == FPGA_FB_DIV_12) {
716 if (vco_div_selection == FPGA_VCO_DIV_6)
717 sys_per = PERIOD_100_00MHZ;
718 if (vco_div_selection == FPGA_VCO_DIV_8)
719 sys_per = PERIOD_75_00MHZ;
720 }
721 break;
722 case PERIOD_66_66MHZ:
723 if (fb_div_selection == FPGA_FB_DIV_6) {
724 if (vco_div_selection == FPGA_VCO_DIV_4)
725 sys_per = PERIOD_100_00MHZ;
726 if (vco_div_selection == FPGA_VCO_DIV_6)
727 sys_per = PERIOD_66_66MHZ;
728 if (vco_div_selection == FPGA_VCO_DIV_8)
729 sys_per = PERIOD_50_00MHZ;
730 }
731 if (fb_div_selection == FPGA_FB_DIV_10) {
732 if (vco_div_selection == FPGA_VCO_DIV_8)
733 sys_per = PERIOD_83_33MHZ;
734 if (vco_div_selection == FPGA_VCO_DIV_10)
735 sys_per = PERIOD_66_66MHZ;
736 }
737 if (fb_div_selection == FPGA_FB_DIV_12) {
738 if (vco_div_selection == FPGA_VCO_DIV_8)
739 sys_per = PERIOD_100_00MHZ;
740 }
741 break;
742 default:
743 break;
744 }
745
746 if (sys_per == 0) {
747 /* Other combinations are not supported */
748 DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
749 hang();
750 }
751 } else {
752 /* calcul system clock without cheking */
753 /* if engineering option clock no check is selected */
754 /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
755 sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
756 }
757
758 return(sys_per);
Marian Balakowicz49d0eee2006-06-30 16:30:46 +0200759}
760
761/*-------------------------------------------------------------------------+
762| determine_pci_clock_per.
763+-------------------------------------------------------------------------*/
764unsigned long determine_pci_clock_per(void)
765{
766 unsigned long pci_clock_selection, pci_period;
767
768 /*-------------------------------------------------------------------------+
769 | Read FPGA reg 6 to get PCI 0 FPGA reg information
770 +-------------------------------------------------------------------------*/
771 pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */
772
773
774 pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
775
776 switch (pci_clock_selection) {
777 case FPGA_REG16_PCI0_CLK_133_33:
778 pci_period = PERIOD_133_33MHZ;
779 break;
780 case FPGA_REG16_PCI0_CLK_100:
781 pci_period = PERIOD_100_00MHZ;
782 break;
783 case FPGA_REG16_PCI0_CLK_66_66:
784 pci_period = PERIOD_66_66MHZ;
785 break;
786 default:
787 pci_period = PERIOD_33_33MHZ;;
788 break;
789 }
790
791 return(pci_period);
wdenk544e9732004-02-06 23:19:44 +0000792}
793#endif
wdenkc6097192002-11-03 00:24:07 +0000794
Michal Simek594c7b52008-06-24 09:54:09 +0200795#elif defined(CONFIG_XILINX_405)
wdenke537b3b2004-02-23 23:54:43 +0000796extern void get_sys_info (sys_info_t * sysInfo);
797extern ulong get_PCI_freq (void);
798
wdenkc6097192002-11-03 00:24:07 +0000799#elif defined(CONFIG_405)
800
Stefan Roese628d3922007-10-22 07:33:52 +0200801void get_sys_info (sys_info_t * sysInfo)
802{
wdenkc6097192002-11-03 00:24:07 +0000803 sysInfo->freqVCOMhz=3125000;
804 sysInfo->freqProcessor=12*1000*1000;
805 sysInfo->freqPLB=50*1000*1000;
806 sysInfo->freqPCI=66*1000*1000;
wdenkc6097192002-11-03 00:24:07 +0000807}
808
stroese434979e2003-05-23 11:18:02 +0000809#elif defined(CONFIG_405EP)
Stefan Roeseedd73f22007-10-21 08:12:41 +0200810void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
stroese434979e2003-05-23 11:18:02 +0000811{
812 unsigned long pllmr0;
813 unsigned long pllmr1;
814 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
815 unsigned long m;
816 unsigned long pllmr0_ccdv;
817
818 /*
819 * Read PLL Mode registers
820 */
Stefan Roese918010a2009-09-09 16:25:29 +0200821 pllmr0 = mfdcr (CPC0_PLLMR0);
822 pllmr1 = mfdcr (CPC0_PLLMR1);
stroese434979e2003-05-23 11:18:02 +0000823
824 /*
825 * Determine forward divider A
826 */
827 sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
828
829 /*
830 * Determine forward divider B (should be equal to A)
831 */
832 sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
833
834 /*
835 * Determine FBK_DIV.
836 */
837 sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
Stefan Roese628d3922007-10-22 07:33:52 +0200838 if (sysInfo->pllFbkDiv == 0)
stroese434979e2003-05-23 11:18:02 +0000839 sysInfo->pllFbkDiv = 16;
stroese434979e2003-05-23 11:18:02 +0000840
841 /*
842 * Determine PLB_DIV.
843 */
844 sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
845
846 /*
847 * Determine PCI_DIV.
848 */
849 sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
850
851 /*
852 * Determine EXTBUS_DIV.
853 */
854 sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
855
856 /*
857 * Determine OPB_DIV.
858 */
859 sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
860
861 /*
862 * Determine the M factor
863 */
864 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
865
866 /*
867 * Determine VCO clock frequency
868 */
stroese5d542f12004-12-16 18:13:53 +0000869 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
870 (unsigned long long)sysClkPeriodPs;
stroese434979e2003-05-23 11:18:02 +0000871
872 /*
873 * Determine CPU clock frequency
874 */
875 pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
876 if (pllmr1 & PLLMR1_SSCS_MASK) {
wdenk99874b42004-07-01 21:40:08 +0000877 /*
878 * This is true if FWDVA == FWDVB:
879 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
880 * / pllmr0_ccdv;
881 */
882 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
883 / sysInfo->pllFwdDiv / pllmr0_ccdv;
stroese434979e2003-05-23 11:18:02 +0000884 } else {
885 sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
886 }
887
888 /*
889 * Determine PLB clock frequency
890 */
891 sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +0200892
893 sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +0200894
Dirk Eibach14857e82009-07-10 14:47:32 +0200895 sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
896
Stefan Roese628d3922007-10-22 07:33:52 +0200897 sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
stroese434979e2003-05-23 11:18:02 +0000898}
899
900
901/********************************************
stroese434979e2003-05-23 11:18:02 +0000902 * get_PCI_freq
903 * return PCI bus freq in Hz
904 *********************************************/
905ulong get_PCI_freq (void)
906{
907 ulong val;
Stefan Roeseedd73f22007-10-21 08:12:41 +0200908 PPC4xx_SYS_INFO sys_info;
stroese434979e2003-05-23 11:18:02 +0000909
910 get_sys_info (&sys_info);
911 val = sys_info.freqPLB / sys_info.pllPciDiv;
912 return val;
913}
914
Stefan Roese17ffbc82007-03-21 13:38:59 +0100915#elif defined(CONFIG_405EZ)
Stefan Roeseedd73f22007-10-21 08:12:41 +0200916void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100917{
918 unsigned long cpr_plld;
Stefan Roese87476ba2007-08-13 09:05:33 +0200919 unsigned long cpr_pllc;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100920 unsigned long cpr_primad;
921 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
922 unsigned long primad_cpudv;
923 unsigned long m;
Stefan Roese17b2d592009-09-11 17:07:55 +0200924 unsigned long plloutb;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100925
926 /*
927 * Read PLL Mode registers
928 */
Stefan Roese918010a2009-09-09 16:25:29 +0200929 mfcpr(CPR0_PLLD, cpr_plld);
930 mfcpr(CPR0_PLLC, cpr_pllc);
Stefan Roese17ffbc82007-03-21 13:38:59 +0100931
932 /*
933 * Determine forward divider A
934 */
935 sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
936
937 /*
Stefan Roese87476ba2007-08-13 09:05:33 +0200938 * Determine forward divider B
Stefan Roese17ffbc82007-03-21 13:38:59 +0100939 */
940 sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
Stefan Roese87476ba2007-08-13 09:05:33 +0200941 if (sysInfo->pllFwdDivB == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100942 sysInfo->pllFwdDivB = 8;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100943
944 /*
945 * Determine FBK_DIV.
946 */
947 sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
Stefan Roese87476ba2007-08-13 09:05:33 +0200948 if (sysInfo->pllFbkDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100949 sysInfo->pllFbkDiv = 256;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100950
951 /*
952 * Read CPR_PRIMAD register
953 */
Stefan Roese8cb251a2010-09-12 06:21:37 +0200954 mfcpr(CPR0_PRIMAD, cpr_primad);
Stefan Roese628d3922007-10-22 07:33:52 +0200955
Stefan Roese17ffbc82007-03-21 13:38:59 +0100956 /*
957 * Determine PLB_DIV.
958 */
959 sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
Stefan Roese87476ba2007-08-13 09:05:33 +0200960 if (sysInfo->pllPlbDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100961 sysInfo->pllPlbDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100962
963 /*
964 * Determine EXTBUS_DIV.
965 */
966 sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
Stefan Roese87476ba2007-08-13 09:05:33 +0200967 if (sysInfo->pllExtBusDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100968 sysInfo->pllExtBusDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100969
970 /*
971 * Determine OPB_DIV.
972 */
973 sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
Stefan Roese87476ba2007-08-13 09:05:33 +0200974 if (sysInfo->pllOpbDiv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100975 sysInfo->pllOpbDiv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100976
977 /*
978 * Determine the M factor
979 */
Stefan Roese87476ba2007-08-13 09:05:33 +0200980 if (cpr_pllc & PLLC_SRC_MASK)
981 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
982 else
983 m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100984
985 /*
986 * Determine VCO clock frequency
987 */
988 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
989 (unsigned long long)sysClkPeriodPs;
990
991 /*
992 * Determine CPU clock frequency
993 */
994 primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
Stefan Roese87476ba2007-08-13 09:05:33 +0200995 if (primad_cpudv == 0)
Stefan Roese17ffbc82007-03-21 13:38:59 +0100996 primad_cpudv = 16;
Stefan Roese17ffbc82007-03-21 13:38:59 +0100997
Stefan Roese87476ba2007-08-13 09:05:33 +0200998 sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
999 sysInfo->pllFwdDiv / primad_cpudv;
Stefan Roese17ffbc82007-03-21 13:38:59 +01001000
1001 /*
1002 * Determine PLB clock frequency
1003 */
Stefan Roese87476ba2007-08-13 09:05:33 +02001004 sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
1005 sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
Stefan Roese153b3e22007-10-05 17:10:59 +02001006
Stefan Roese11f51692009-09-14 11:13:34 +02001007 sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1008 sysInfo->pllOpbDiv;
1009
Stefan Roese153b3e22007-10-05 17:10:59 +02001010 sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
1011 sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +02001012
Stefan Roese17b2d592009-09-11 17:07:55 +02001013 plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
1014 sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
1015 sysInfo->pllFwdDivB);
1016 sysInfo->freqUART = plloutb;
Stefan Roese17ffbc82007-03-21 13:38:59 +01001017}
1018
Stefan Roese153b3e22007-10-05 17:10:59 +02001019#elif defined(CONFIG_405EX)
1020
1021/*
1022 * TODO: We need to get the CPR registers and calculate these values correctly!!!!
1023 * We need the specs!!!!
1024 */
1025static unsigned char get_fbdv(unsigned char index)
1026{
1027 unsigned char ret = 0;
1028 /* This is table should be 256 bytes.
1029 * Only take first 52 values.
1030 */
1031 unsigned char fbdv_tb[] = {
1032 0x00, 0xff, 0x7f, 0xfd,
1033 0x7a, 0xf5, 0x6a, 0xd5,
1034 0x2a, 0xd4, 0x29, 0xd3,
1035 0x26, 0xcc, 0x19, 0xb3,
1036 0x67, 0xce, 0x1d, 0xbb,
1037 0x77, 0xee, 0x5d, 0xba,
1038 0x74, 0xe9, 0x52, 0xa5,
1039 0x4b, 0x96, 0x2c, 0xd8,
1040 0x31, 0xe3, 0x46, 0x8d,
1041 0x1b, 0xb7, 0x6f, 0xde,
1042 0x3d, 0xfb, 0x76, 0xed,
1043 0x5a, 0xb5, 0x6b, 0xd6,
1044 0x2d, 0xdb, 0x36, 0xec,
1045
1046 };
1047
1048 if ((index & 0x7f) == 0)
1049 return 1;
1050 while (ret < sizeof (fbdv_tb)) {
1051 if (fbdv_tb[ret] == index)
1052 break;
1053 ret++;
1054 }
1055 ret++;
1056
1057 return ret;
1058}
1059
1060#define PLL_FBK_PLL_LOCAL 0
1061#define PLL_FBK_CPU 1
1062#define PLL_FBK_PERCLK 5
1063
1064void get_sys_info (sys_info_t * sysInfo)
1065{
1066 unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1067 unsigned long m = 1;
1068 unsigned int tmp;
1069 unsigned char fwdva[16] = {
1070 1, 2, 14, 9, 4, 11, 16, 13,
1071 12, 5, 6, 15, 10, 7, 8, 3,
1072 };
1073 unsigned char sel, cpudv0, plb2xDiv;
1074
Stefan Roese918010a2009-09-09 16:25:29 +02001075 mfcpr(CPR0_PLLD, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001076
1077 /*
1078 * Determine forward divider A
1079 */
1080 sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)]; /* FWDVA */
1081
1082 /*
1083 * Determine FBK_DIV.
1084 */
1085 sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1086
1087 /*
1088 * Determine PLBDV0
1089 */
1090 sysInfo->pllPlbDiv = 2;
1091
1092 /*
1093 * Determine PERDV0
1094 */
Stefan Roese918010a2009-09-09 16:25:29 +02001095 mfcpr(CPR0_PERD, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001096 tmp = (tmp >> 24) & 0x03;
1097 sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1098
1099 /*
1100 * Determine OPBDV0
1101 */
Niklaus Giger728bd0a2009-10-04 20:04:20 +02001102 mfcpr(CPR0_OPBD0, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001103 tmp = (tmp >> 24) & 0x03;
1104 sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1105
1106 /* Determine PLB2XDV0 */
Stefan Roese918010a2009-09-09 16:25:29 +02001107 mfcpr(CPR0_PLBD, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001108 tmp = (tmp >> 16) & 0x07;
1109 plb2xDiv = (tmp == 0) ? 8 : tmp;
1110
1111 /* Determine CPUDV0 */
Stefan Roese918010a2009-09-09 16:25:29 +02001112 mfcpr(CPR0_CPUD, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001113 tmp = (tmp >> 24) & 0x07;
1114 cpudv0 = (tmp == 0) ? 8 : tmp;
1115
1116 /* Determine SEL(5:7) in CPR0_PLLC */
Stefan Roese918010a2009-09-09 16:25:29 +02001117 mfcpr(CPR0_PLLC, tmp);
Stefan Roese153b3e22007-10-05 17:10:59 +02001118 sel = (tmp >> 24) & 0x07;
1119
1120 /*
1121 * Determine the M factor
1122 * PLL local: M = FBDV
1123 * CPU clock: M = FBDV * FWDVA * CPUDV0
1124 * PerClk : M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1125 *
1126 */
1127 switch (sel) {
1128 case PLL_FBK_CPU:
1129 m = sysInfo->pllFwdDiv * cpudv0;
1130 break;
1131 case PLL_FBK_PERCLK:
1132 m = sysInfo->pllFwdDiv * plb2xDiv * 2
1133 * sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1134 break;
Wolfgang Denka1be4762008-05-20 16:00:29 +02001135 case PLL_FBK_PLL_LOCAL:
Stefan Roese153b3e22007-10-05 17:10:59 +02001136 break;
1137 default:
1138 printf("%s unknown m\n", __FUNCTION__);
1139 return;
1140
1141 }
1142 m *= sysInfo->pllFbkDiv;
1143
1144 /*
1145 * Determine VCO clock frequency
1146 */
1147 sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1148 (unsigned long long)sysClkPeriodPs;
1149
1150 /*
1151 * Determine CPU clock frequency
1152 */
1153 sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1154
1155 /*
1156 * Determine PLB clock frequency, ddr1x should be the same
1157 */
1158 sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1159 sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1160 sysInfo->freqDDR = sysInfo->freqPLB;
1161 sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
Stefan Roese628d3922007-10-22 07:33:52 +02001162 sysInfo->freqUART = sysInfo->freqPLB;
Stefan Roese153b3e22007-10-05 17:10:59 +02001163}
1164
wdenkc6097192002-11-03 00:24:07 +00001165#endif
1166
1167int get_clocks (void)
1168{
wdenkc6097192002-11-03 00:24:07 +00001169 sys_info_t sys_info;
1170
1171 get_sys_info (&sys_info);
1172 gd->cpu_clk = sys_info.freqProcessor;
1173 gd->bus_clk = sys_info.freqPLB;
1174
wdenkc6097192002-11-03 00:24:07 +00001175 return (0);
1176}
1177
1178
1179/********************************************
1180 * get_bus_freq
1181 * return PLB bus freq in Hz
1182 *********************************************/
1183ulong get_bus_freq (ulong dummy)
1184{
1185 ulong val;
1186
Matthias Fuchse54a67f2013-08-07 12:10:38 +02001187#if defined(CONFIG_405GP) || \
Stefan Roese17ffbc82007-03-21 13:38:59 +01001188 defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
Stefan Roese153b3e22007-10-05 17:10:59 +02001189 defined(CONFIG_405EX) || defined(CONFIG_405) || \
1190 defined(CONFIG_440)
wdenkc6097192002-11-03 00:24:07 +00001191 sys_info_t sys_info;
1192
1193 get_sys_info (&sys_info);
1194 val = sys_info.freqPLB;
wdenkc6097192002-11-03 00:24:07 +00001195#else
1196# error get_bus_freq() not implemented
1197#endif
1198
1199 return val;
1200}
Stefan Roese11f51692009-09-14 11:13:34 +02001201
Stefan Roese11f51692009-09-14 11:13:34 +02001202ulong get_OPB_freq (void)
1203{
1204 PPC4xx_SYS_INFO sys_info;
1205
1206 get_sys_info (&sys_info);
1207
1208 return sys_info.freqOPB;
1209}