1 /*
2  * (C) Copyright 2000-2008
3  * 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 
29 DECLARE_GLOBAL_DATA_PTR;
30 
31 #define ONE_BILLION        1000000000
32 #ifdef DEBUG
33 #define DEBUGF(fmt,args...) printf(fmt ,##args)
34 #else
35 #define DEBUGF(fmt,args...)
36 #endif
37 
38 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
39 
40 #if defined(CONFIG_405GP) || defined(CONFIG_405CR)
41 
get_sys_info(PPC4xx_SYS_INFO * sysInfo)42 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
43 {
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 (CPC0_PLLMR);
54 
55 	/*
56 	 * Read Pin Strapping register
57 	 */
58 	psr = mfdcr (CPC0_PSR);
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 	 */
96 	if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) {
97 		/*
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 
141 		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);
145 	} 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 {
157 			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;
165 		}
166 	}
167 
168 	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
169 	sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
170 	sysInfo->freqUART = sysInfo->freqProcessor;
171 }
172 
173 
174 /********************************************
175  * get_PCI_freq
176  * return PCI bus freq in Hz
177  *********************************************/
get_PCI_freq(void)178 ulong get_PCI_freq (void)
179 {
180 	ulong val;
181 	PPC4xx_SYS_INFO sys_info;
182 
183 	get_sys_info (&sys_info);
184 	val = sys_info.freqPLB / sys_info.pllPciDiv;
185 	return val;
186 }
187 
188 
189 #elif defined(CONFIG_440)
190 
191 #if defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
192     defined(CONFIG_460SX)
193 static u8 pll_fwdv_multi_bits[] = {
194 	/* values for:  1 - 16 */
195 	0x00, 0x01, 0x0f, 0x04, 0x09, 0x0a, 0x0d, 0x0e, 0x03, 0x0c,
196 	0x05, 0x08, 0x07, 0x02, 0x0b, 0x06
197 };
198 
get_cpr0_fwdv(unsigned long cpr_reg_fwdv)199 u32 get_cpr0_fwdv(unsigned long cpr_reg_fwdv)
200 {
201 	u32 index;
202 
203 	for (index = 0; index < ARRAY_SIZE(pll_fwdv_multi_bits); index++)
204 		if (cpr_reg_fwdv == (u32)pll_fwdv_multi_bits[index])
205 			return index + 1;
206 
207 	return 0;
208 }
209 
210 static u8 pll_fbdv_multi_bits[] = {
211 	/* values for:  1 - 100 */
212 	0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
213 	0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
214 	0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
215 	0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
216 	0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
217 	0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
218 	0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
219 	0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
220 	0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
221 	0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
222 	/* values for:  101 - 200 */
223 	0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
224 	0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
225 	0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
226 	0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
227 	0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
228 	0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
229 	0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
230 	0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
231 	0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
232 	0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
233 	/* values for:  201 - 255 */
234 	0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
235 	0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
236 	0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
237 	0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
238 	0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
239 	0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
240 };
241 
get_cpr0_fbdv(unsigned long cpr_reg_fbdv)242 u32 get_cpr0_fbdv(unsigned long cpr_reg_fbdv)
243 {
244 	u32 index;
245 
246 	for (index = 0; index < ARRAY_SIZE(pll_fbdv_multi_bits); index++)
247 		if (cpr_reg_fbdv == (u32)pll_fbdv_multi_bits[index])
248 			return index + 1;
249 
250 	return 0;
251 }
252 
253 /*
254  * AMCC_TODO: verify this routine against latest EAS, cause stuff changed
255  *            with latest EAS
256  */
get_sys_info(sys_info_t * sysInfo)257 void get_sys_info (sys_info_t * sysInfo)
258 {
259 	unsigned long strp0;
260 	unsigned long strp1;
261 	unsigned long temp;
262 	unsigned long m;
263 	unsigned long plbedv0;
264 
265 	/* Extract configured divisors */
266 	mfsdr(SDR0_SDSTP0, strp0);
267 	mfsdr(SDR0_SDSTP1, strp1);
268 
269 	temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 4);
270 	sysInfo->pllFwdDivA = get_cpr0_fwdv(temp);
271 
272 	temp = (strp0 & PLLSYS0_FWD_DIV_B_MASK);
273 	sysInfo->pllFwdDivB = get_cpr0_fwdv(temp);
274 
275 	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 8;
276 	sysInfo->pllFbkDiv = get_cpr0_fbdv(temp);
277 
278 	temp = (strp1 & PLLSYS0_OPB_DIV_MASK) >> 26;
279 	sysInfo->pllOpbDiv = temp ? temp : 4;
280 
281 	/* AMCC_TODO: verify the SDR0_SDSTP1.PERDV0 value sysInfo->pllExtBusDiv */
282 	temp = (strp1 & PLLSYS0_PERCLK_DIV_MASK) >> 24;
283 	sysInfo->pllExtBusDiv = temp ? temp : 4;
284 
285 	temp = (strp1 & PLLSYS0_PLBEDV0_DIV_MASK) >> 29;
286 	plbedv0 = temp ? temp: 8;
287 
288 	/* Calculate 'M' based on feedback source */
289 	temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
290 	if (temp == 0) {
291 		/* PLL internal feedback */
292 		m = sysInfo->pllFbkDiv;
293 	} else {
294 		/* PLL PerClk feedback */
295 		m = sysInfo->pllFwdDivA * plbedv0 * sysInfo->pllOpbDiv *
296 			sysInfo->pllExtBusDiv;
297 	}
298 
299 	/* Now calculate the individual clocks */
300 	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
301 	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
302 	sysInfo->freqPLB = sysInfo->freqVCOMhz / sysInfo->pllFwdDivA / plbedv0;
303 	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
304 	sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
305 	sysInfo->freqDDR = sysInfo->freqPLB;
306 	sysInfo->freqUART = sysInfo->freqPLB;
307 
308 	return;
309 }
310 
311 #elif defined(CONFIG_440EP) || defined(CONFIG_440GR) || \
312     defined(CONFIG_440EPX) || defined(CONFIG_440GRX)
get_sys_info(sys_info_t * sysInfo)313 void get_sys_info (sys_info_t *sysInfo)
314 {
315 	unsigned long temp;
316 	unsigned long reg;
317 	unsigned long lfdiv;
318 	unsigned long m;
319 	unsigned long prbdv0;
320 	/*
321 	  WARNING: ASSUMES the following:
322 	  ENG=1
323 	  PRADV0=1
324 	  PRBDV0=1
325 	*/
326 
327 	/* Decode CPR0_PLLD0 for divisors */
328 	mfcpr(CPR0_PLLD, reg);
329 	temp = (reg & PLLD_FWDVA_MASK) >> 16;
330 	sysInfo->pllFwdDivA = temp ? temp : 16;
331 	temp = (reg & PLLD_FWDVB_MASK) >> 8;
332 	sysInfo->pllFwdDivB = temp ? temp: 8 ;
333 	temp = (reg & PLLD_FBDV_MASK) >> 24;
334 	sysInfo->pllFbkDiv = temp ? temp : 32;
335 	lfdiv = reg & PLLD_LFBDV_MASK;
336 
337 	mfcpr(CPR0_OPBD0, reg);
338 	temp = (reg & OPBDDV_MASK) >> 24;
339 	sysInfo->pllOpbDiv = temp ? temp : 4;
340 
341 	mfcpr(CPR0_PERD, reg);
342 	temp = (reg & PERDV_MASK) >> 24;
343 	sysInfo->pllExtBusDiv = temp ? temp : 8;
344 
345 	mfcpr(CPR0_PRIMBD0, reg);
346 	temp = (reg & PRBDV_MASK) >> 24;
347 	prbdv0 = temp ? temp : 8;
348 
349 	mfcpr(CPR0_SPCID, reg);
350 	temp = (reg & SPCID_MASK) >> 24;
351 	sysInfo->pllPciDiv = temp ? temp : 4;
352 
353 	/* Calculate 'M' based on feedback source */
354 	mfsdr(SDR0_SDSTP0, reg);
355 	temp = (reg & PLLSYS0_SEL_MASK) >> 27;
356 	if (temp == 0) { /* PLL output */
357 		/* Figure which pll to use */
358 		mfcpr(CPR0_PLLC, reg);
359 		temp = (reg & PLLC_SRC_MASK) >> 29;
360 		if (!temp) /* PLLOUTA */
361 			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
362 		else       /* PLLOUTB */
363 			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
364 	}
365 	else if (temp == 1) /* CPU output */
366 		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
367 	else /* PerClk */
368 		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
369 
370 	/* Now calculate the individual clocks */
371 	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
372 	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
373 	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
374 	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
375 	sysInfo->freqEBC = sysInfo->freqPLB/sysInfo->pllExtBusDiv;
376 	sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv;
377 	sysInfo->freqUART = sysInfo->freqPLB;
378 
379 	/* Figure which timer source to use */
380 	if (mfspr(SPRN_CCR1) & 0x0080) {
381 		/* External Clock, assume same as SYS_CLK */
382 		temp = sysInfo->freqProcessor / 2;  /* Max extern clock speed */
383 		if (CONFIG_SYS_CLK_FREQ > temp)
384 			sysInfo->freqTmrClk = temp;
385 		else
386 			sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ;
387 	}
388 	else  /* Internal clock */
389 		sysInfo->freqTmrClk = sysInfo->freqProcessor;
390 }
391 
392 /********************************************
393  * get_PCI_freq
394  * return PCI bus freq in Hz
395  *********************************************/
get_PCI_freq(void)396 ulong get_PCI_freq (void)
397 {
398 	sys_info_t sys_info;
399 	get_sys_info (&sys_info);
400 	return sys_info.freqPCI;
401 }
402 
403 #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) \
404 	&& !defined(CONFIG_XILINX_440)
get_sys_info(sys_info_t * sysInfo)405 void get_sys_info (sys_info_t * sysInfo)
406 {
407 	unsigned long strp0;
408 	unsigned long temp;
409 	unsigned long m;
410 
411 	/* Extract configured divisors */
412 	strp0 = mfdcr( CPC0_STRP0 );
413 	sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15);
414 	sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12);
415 	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18;
416 	sysInfo->pllFbkDiv = temp ? temp : 16;
417 	sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10);
418 	sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8);
419 
420 	/* Calculate 'M' based on feedback source */
421 	if( strp0 & PLLSYS0_EXTSL_MASK )
422 		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
423 	else
424 		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
425 
426 	/* Now calculate the individual clocks */
427 	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1);
428 	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
429 	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB;
430 	if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */
431 		sysInfo->freqPLB >>= 1;
432 	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
433 	sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
434 	sysInfo->freqUART = sysInfo->freqPLB;
435 }
436 #else
437 
438 #if !defined(CONFIG_XILINX_440)
get_sys_info(sys_info_t * sysInfo)439 void get_sys_info (sys_info_t * sysInfo)
440 {
441 	unsigned long strp0;
442 	unsigned long strp1;
443 	unsigned long temp;
444 	unsigned long temp1;
445 	unsigned long lfdiv;
446 	unsigned long m;
447 	unsigned long prbdv0;
448 
449 #if defined(CONFIG_YUCCA)
450 	unsigned long sys_freq;
451 	unsigned long sys_per=0;
452 	unsigned long msr;
453 	unsigned long pci_clock_per;
454 	unsigned long sdr_ddrpll;
455 
456 	/*-------------------------------------------------------------------------+
457 	 | Get the system clock period.
458 	 +-------------------------------------------------------------------------*/
459 	sys_per = determine_sysper();
460 
461 	msr = (mfmsr () & ~(MSR_EE));	/* disable interrupts */
462 
463 	/*-------------------------------------------------------------------------+
464 	 | Calculate the system clock speed from the period.
465 	 +-------------------------------------------------------------------------*/
466 	sys_freq = (ONE_BILLION / sys_per) * 1000;
467 #endif
468 
469 	/* Extract configured divisors */
470 	mfsdr( SDR0_SDSTP0,strp0 );
471 	mfsdr( SDR0_SDSTP1,strp1 );
472 
473 	temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8);
474 	sysInfo->pllFwdDivA = temp ? temp : 16 ;
475 	temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5);
476 	sysInfo->pllFwdDivB = temp ? temp: 8 ;
477 	temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12;
478 	sysInfo->pllFbkDiv = temp ? temp : 32;
479 	temp = (strp0 & PLLSYS0_OPB_DIV_MASK);
480 	sysInfo->pllOpbDiv = temp ? temp : 4;
481 	temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24;
482 	sysInfo->pllExtBusDiv = temp ? temp : 4;
483 	prbdv0 = (strp0 >> 2) & 0x7;
484 
485 	/* Calculate 'M' based on feedback source */
486 	temp = (strp0 & PLLSYS0_SEL_MASK) >> 27;
487 	temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26;
488 	lfdiv = temp1 ? temp1 : 64;
489 	if (temp == 0) { /* PLL output */
490 		/* Figure which pll to use */
491 		temp = (strp0 & PLLSYS0_SRC_MASK) >> 30;
492 		if (!temp)
493 			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA;
494 		else
495 			m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB;
496 	}
497 	else if (temp == 1) /* CPU output */
498 		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA;
499 	else /* PerClk */
500 		m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB;
501 
502 	/* Now calculate the individual clocks */
503 #if defined(CONFIG_YUCCA)
504 	sysInfo->freqVCOMhz = (m * sys_freq) ;
505 #else
506 	sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1);
507 #endif
508 	sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA;
509 	sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0;
510 	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
511 	sysInfo->freqEBC = sysInfo->freqOPB/sysInfo->pllExtBusDiv;
512 
513 #if defined(CONFIG_YUCCA)
514 	/* Determine PCI Clock Period */
515 	pci_clock_per = determine_pci_clock_per();
516 	sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000;
517 	mfsdr(SDR0_DDR0, sdr_ddrpll);
518 	sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll));
519 #endif
520 
521 	sysInfo->freqUART = sysInfo->freqPLB;
522 }
523 
524 #endif
525 #endif /* CONFIG_XILINX_440 */
526 
527 #if defined(CONFIG_YUCCA)
determine_sysper(void)528 unsigned long determine_sysper(void)
529 {
530 	unsigned int fpga_clocking_reg;
531 	unsigned int master_clock_selection;
532 	unsigned long master_clock_per = 0;
533 	unsigned long fb_div_selection;
534 	unsigned int vco_div_reg_value;
535 	unsigned long vco_div_selection;
536 	unsigned long sys_per = 0;
537 	int extClkVal;
538 
539 	/*-------------------------------------------------------------------------+
540 	 | Read FPGA reg 0 and reg 1 to get FPGA reg information
541 	 +-------------------------------------------------------------------------*/
542 	fpga_clocking_reg = in16(FPGA_REG16);
543 
544 
545 	/* Determine Master Clock Source Selection */
546 	master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK;
547 
548 	switch(master_clock_selection) {
549 		case FPGA_REG16_MASTER_CLK_66_66:
550 			master_clock_per = PERIOD_66_66MHZ;
551 			break;
552 		case FPGA_REG16_MASTER_CLK_50:
553 			master_clock_per = PERIOD_50_00MHZ;
554 			break;
555 		case FPGA_REG16_MASTER_CLK_33_33:
556 			master_clock_per = PERIOD_33_33MHZ;
557 			break;
558 		case FPGA_REG16_MASTER_CLK_25:
559 			master_clock_per = PERIOD_25_00MHZ;
560 			break;
561 		case FPGA_REG16_MASTER_CLK_EXT:
562 			if ((extClkVal==EXTCLK_33_33)
563 					&& (extClkVal==EXTCLK_50)
564 					&& (extClkVal==EXTCLK_66_66)
565 					&& (extClkVal==EXTCLK_83)) {
566 				/* calculate master clock period from external clock value */
567 				master_clock_per=(ONE_BILLION/extClkVal) * 1000;
568 			} else {
569 				/* Unsupported */
570 				DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
571 				hang();
572 			}
573 			break;
574 		default:
575 			/* Unsupported */
576 			DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__);
577 			hang();
578 			break;
579 	}
580 
581 	/* Determine FB divisors values */
582 	if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) {
583 		if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
584 			fb_div_selection = FPGA_FB_DIV_6;
585 		else
586 			fb_div_selection = FPGA_FB_DIV_12;
587 	} else {
588 		if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW)
589 			fb_div_selection = FPGA_FB_DIV_10;
590 		else
591 			fb_div_selection = FPGA_FB_DIV_20;
592 	}
593 
594 	/* Determine VCO divisors values */
595 	vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK;
596 
597 	switch(vco_div_reg_value) {
598 		case FPGA_REG16_VCO_DIV_4:
599 			vco_div_selection = FPGA_VCO_DIV_4;
600 			break;
601 		case FPGA_REG16_VCO_DIV_6:
602 			vco_div_selection = FPGA_VCO_DIV_6;
603 			break;
604 		case FPGA_REG16_VCO_DIV_8:
605 			vco_div_selection = FPGA_VCO_DIV_8;
606 			break;
607 		case FPGA_REG16_VCO_DIV_10:
608 		default:
609 			vco_div_selection = FPGA_VCO_DIV_10;
610 			break;
611 	}
612 
613 	if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) {
614 		switch(master_clock_per) {
615 			case PERIOD_25_00MHZ:
616 				if (fb_div_selection == FPGA_FB_DIV_12) {
617 					if (vco_div_selection == FPGA_VCO_DIV_4)
618 						sys_per = PERIOD_75_00MHZ;
619 					if (vco_div_selection == FPGA_VCO_DIV_6)
620 						sys_per = PERIOD_50_00MHZ;
621 				}
622 				break;
623 			case PERIOD_33_33MHZ:
624 				if (fb_div_selection == FPGA_FB_DIV_6) {
625 					if (vco_div_selection == FPGA_VCO_DIV_4)
626 						sys_per = PERIOD_50_00MHZ;
627 					if (vco_div_selection == FPGA_VCO_DIV_6)
628 						sys_per = PERIOD_33_33MHZ;
629 				}
630 				if (fb_div_selection == FPGA_FB_DIV_10) {
631 					if (vco_div_selection == FPGA_VCO_DIV_4)
632 						sys_per = PERIOD_83_33MHZ;
633 					if (vco_div_selection == FPGA_VCO_DIV_10)
634 						sys_per = PERIOD_33_33MHZ;
635 				}
636 				if (fb_div_selection == FPGA_FB_DIV_12) {
637 					if (vco_div_selection == FPGA_VCO_DIV_4)
638 						sys_per = PERIOD_100_00MHZ;
639 					if (vco_div_selection == FPGA_VCO_DIV_6)
640 						sys_per = PERIOD_66_66MHZ;
641 					if (vco_div_selection == FPGA_VCO_DIV_8)
642 						sys_per = PERIOD_50_00MHZ;
643 				}
644 				break;
645 			case PERIOD_50_00MHZ:
646 				if (fb_div_selection == FPGA_FB_DIV_6) {
647 					if (vco_div_selection == FPGA_VCO_DIV_4)
648 						sys_per = PERIOD_75_00MHZ;
649 					if (vco_div_selection == FPGA_VCO_DIV_6)
650 						sys_per = PERIOD_50_00MHZ;
651 				}
652 				if (fb_div_selection == FPGA_FB_DIV_10) {
653 					if (vco_div_selection == FPGA_VCO_DIV_6)
654 						sys_per = PERIOD_83_33MHZ;
655 					if (vco_div_selection == FPGA_VCO_DIV_10)
656 						sys_per = PERIOD_50_00MHZ;
657 				}
658 				if (fb_div_selection == FPGA_FB_DIV_12) {
659 					if (vco_div_selection == FPGA_VCO_DIV_6)
660 						sys_per = PERIOD_100_00MHZ;
661 					if (vco_div_selection == FPGA_VCO_DIV_8)
662 						sys_per = PERIOD_75_00MHZ;
663 				}
664 				break;
665 			case PERIOD_66_66MHZ:
666 				if (fb_div_selection == FPGA_FB_DIV_6) {
667 					if (vco_div_selection == FPGA_VCO_DIV_4)
668 						sys_per = PERIOD_100_00MHZ;
669 					if (vco_div_selection == FPGA_VCO_DIV_6)
670 						sys_per = PERIOD_66_66MHZ;
671 					if (vco_div_selection == FPGA_VCO_DIV_8)
672 						sys_per = PERIOD_50_00MHZ;
673 				}
674 				if (fb_div_selection == FPGA_FB_DIV_10) {
675 					if (vco_div_selection == FPGA_VCO_DIV_8)
676 						sys_per = PERIOD_83_33MHZ;
677 					if (vco_div_selection == FPGA_VCO_DIV_10)
678 						sys_per = PERIOD_66_66MHZ;
679 				}
680 				if (fb_div_selection == FPGA_FB_DIV_12) {
681 					if (vco_div_selection == FPGA_VCO_DIV_8)
682 						sys_per = PERIOD_100_00MHZ;
683 				}
684 				break;
685 			default:
686 				break;
687 		}
688 
689 		if (sys_per == 0) {
690 			/* Other combinations are not supported */
691 			DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__);
692 			hang();
693 		}
694 	} else {
695 		/* calcul system clock without cheking */
696 		/* if engineering option clock no check is selected */
697 		/* sys_per = master_clock_per * vco_div_selection / fb_div_selection */
698 		sys_per = (master_clock_per/fb_div_selection) * vco_div_selection;
699 	}
700 
701 	return(sys_per);
702 }
703 
704 /*-------------------------------------------------------------------------+
705 | determine_pci_clock_per.
706 +-------------------------------------------------------------------------*/
determine_pci_clock_per(void)707 unsigned long determine_pci_clock_per(void)
708 {
709 	unsigned long pci_clock_selection,  pci_period;
710 
711 	/*-------------------------------------------------------------------------+
712 	 | Read FPGA reg 6 to get PCI 0 FPGA reg information
713 	 +-------------------------------------------------------------------------*/
714 	pci_clock_selection = in16(FPGA_REG16);	/* was reg6 averifier */
715 
716 
717 	pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK;
718 
719 	switch (pci_clock_selection) {
720 		case FPGA_REG16_PCI0_CLK_133_33:
721 			pci_period = PERIOD_133_33MHZ;
722 			break;
723 		case FPGA_REG16_PCI0_CLK_100:
724 			pci_period = PERIOD_100_00MHZ;
725 			break;
726 		case FPGA_REG16_PCI0_CLK_66_66:
727 			pci_period = PERIOD_66_66MHZ;
728 			break;
729 		default:
730 			pci_period = PERIOD_33_33MHZ;;
731 			break;
732 	}
733 
734 	return(pci_period);
735 }
736 #endif
737 
738 #elif defined(CONFIG_XILINX_405)
739 extern void get_sys_info (sys_info_t * sysInfo);
740 extern ulong get_PCI_freq (void);
741 
742 #elif defined(CONFIG_AP1000)
get_sys_info(sys_info_t * sysInfo)743 void get_sys_info (sys_info_t * sysInfo)
744 {
745 	sysInfo->freqProcessor = 240 * 1000 * 1000;
746 	sysInfo->freqPLB = 80 * 1000 * 1000;
747 	sysInfo->freqPCI = 33 * 1000 * 1000;
748 }
749 
750 #elif defined(CONFIG_405)
751 
get_sys_info(sys_info_t * sysInfo)752 void get_sys_info (sys_info_t * sysInfo)
753 {
754 	sysInfo->freqVCOMhz=3125000;
755 	sysInfo->freqProcessor=12*1000*1000;
756 	sysInfo->freqPLB=50*1000*1000;
757 	sysInfo->freqPCI=66*1000*1000;
758 }
759 
760 #elif defined(CONFIG_405EP)
get_sys_info(PPC4xx_SYS_INFO * sysInfo)761 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
762 {
763 	unsigned long pllmr0;
764 	unsigned long pllmr1;
765 	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
766 	unsigned long m;
767 	unsigned long pllmr0_ccdv;
768 
769 	/*
770 	 * Read PLL Mode registers
771 	 */
772 	pllmr0 = mfdcr (CPC0_PLLMR0);
773 	pllmr1 = mfdcr (CPC0_PLLMR1);
774 
775 	/*
776 	 * Determine forward divider A
777 	 */
778 	sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16);
779 
780 	/*
781 	 * Determine forward divider B (should be equal to A)
782 	 */
783 	sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12);
784 
785 	/*
786 	 * Determine FBK_DIV.
787 	 */
788 	sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20);
789 	if (sysInfo->pllFbkDiv == 0)
790 		sysInfo->pllFbkDiv = 16;
791 
792 	/*
793 	 * Determine PLB_DIV.
794 	 */
795 	sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1;
796 
797 	/*
798 	 * Determine PCI_DIV.
799 	 */
800 	sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1;
801 
802 	/*
803 	 * Determine EXTBUS_DIV.
804 	 */
805 	sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2;
806 
807 	/*
808 	 * Determine OPB_DIV.
809 	 */
810 	sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1;
811 
812 	/*
813 	 * Determine the M factor
814 	 */
815 	m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
816 
817 	/*
818 	 * Determine VCO clock frequency
819 	 */
820 	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
821 		(unsigned long long)sysClkPeriodPs;
822 
823 	/*
824 	 * Determine CPU clock frequency
825 	 */
826 	pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1;
827 	if (pllmr1 & PLLMR1_SSCS_MASK) {
828 		/*
829 		 * This is true if FWDVA == FWDVB:
830 		 * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv)
831 		 *	/ pllmr0_ccdv;
832 		 */
833 		sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB)
834 			/ sysInfo->pllFwdDiv / pllmr0_ccdv;
835 	} else {
836 		sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv;
837 	}
838 
839 	/*
840 	 * Determine PLB clock frequency
841 	 */
842 	sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv;
843 
844 	sysInfo->freqEBC = sysInfo->freqPLB / sysInfo->pllExtBusDiv;
845 
846 	sysInfo->freqOPB = sysInfo->freqPLB / sysInfo->pllOpbDiv;
847 
848 	sysInfo->freqUART = sysInfo->freqProcessor * pllmr0_ccdv;
849 }
850 
851 
852 /********************************************
853  * get_PCI_freq
854  * return PCI bus freq in Hz
855  *********************************************/
get_PCI_freq(void)856 ulong get_PCI_freq (void)
857 {
858 	ulong val;
859 	PPC4xx_SYS_INFO sys_info;
860 
861 	get_sys_info (&sys_info);
862 	val = sys_info.freqPLB / sys_info.pllPciDiv;
863 	return val;
864 }
865 
866 #elif defined(CONFIG_405EZ)
get_sys_info(PPC4xx_SYS_INFO * sysInfo)867 void get_sys_info (PPC4xx_SYS_INFO * sysInfo)
868 {
869 	unsigned long cpr_plld;
870 	unsigned long cpr_pllc;
871 	unsigned long cpr_primad;
872 	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000);
873 	unsigned long primad_cpudv;
874 	unsigned long m;
875 	unsigned long plloutb;
876 
877 	/*
878 	 * Read PLL Mode registers
879 	 */
880 	mfcpr(CPR0_PLLD, cpr_plld);
881 	mfcpr(CPR0_PLLC, cpr_pllc);
882 
883 	/*
884 	 * Determine forward divider A
885 	 */
886 	sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16);
887 
888 	/*
889 	 * Determine forward divider B
890 	 */
891 	sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8);
892 	if (sysInfo->pllFwdDivB == 0)
893 		sysInfo->pllFwdDivB = 8;
894 
895 	/*
896 	 * Determine FBK_DIV.
897 	 */
898 	sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24);
899 	if (sysInfo->pllFbkDiv == 0)
900 		sysInfo->pllFbkDiv = 256;
901 
902 	/*
903 	 * Read CPR_PRIMAD register
904 	 */
905 	mfcpr(CPC0_PRIMAD, cpr_primad);
906 
907 	/*
908 	 * Determine PLB_DIV.
909 	 */
910 	sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16);
911 	if (sysInfo->pllPlbDiv == 0)
912 		sysInfo->pllPlbDiv = 16;
913 
914 	/*
915 	 * Determine EXTBUS_DIV.
916 	 */
917 	sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK);
918 	if (sysInfo->pllExtBusDiv == 0)
919 		sysInfo->pllExtBusDiv = 16;
920 
921 	/*
922 	 * Determine OPB_DIV.
923 	 */
924 	sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8);
925 	if (sysInfo->pllOpbDiv == 0)
926 		sysInfo->pllOpbDiv = 16;
927 
928 	/*
929 	 * Determine the M factor
930 	 */
931 	if (cpr_pllc & PLLC_SRC_MASK)
932 		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB;
933 	else
934 		m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv;
935 
936 	/*
937 	 * Determine VCO clock frequency
938 	 */
939 	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
940 		(unsigned long long)sysClkPeriodPs;
941 
942 	/*
943 	 * Determine CPU clock frequency
944 	 */
945 	primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24);
946 	if (primad_cpudv == 0)
947 		primad_cpudv = 16;
948 
949 	sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) /
950 		sysInfo->pllFwdDiv / primad_cpudv;
951 
952 	/*
953 	 * Determine PLB clock frequency
954 	 */
955 	sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) /
956 		sysInfo->pllFwdDiv / sysInfo->pllPlbDiv;
957 
958 	sysInfo->freqOPB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
959 		sysInfo->pllOpbDiv;
960 
961 	sysInfo->freqEBC = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) /
962 		sysInfo->pllExtBusDiv;
963 
964 	plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ?
965 		sysInfo->pllFwdDivB : sysInfo->pllFwdDiv) * sysInfo->pllFbkDiv) /
966 		sysInfo->pllFwdDivB);
967 	sysInfo->freqUART = plloutb;
968 }
969 
970 #elif defined(CONFIG_405EX)
971 
972 /*
973  * TODO: We need to get the CPR registers and calculate these values correctly!!!!
974  *   We need the specs!!!!
975  */
get_fbdv(unsigned char index)976 static unsigned char get_fbdv(unsigned char index)
977 {
978 	unsigned char ret = 0;
979 	/* This is table should be 256 bytes.
980 	 * Only take first 52 values.
981 	 */
982 	unsigned char fbdv_tb[] = {
983 		0x00, 0xff, 0x7f, 0xfd,
984 		0x7a, 0xf5, 0x6a, 0xd5,
985 		0x2a, 0xd4, 0x29, 0xd3,
986 		0x26, 0xcc, 0x19, 0xb3,
987 		0x67, 0xce, 0x1d, 0xbb,
988 		0x77, 0xee, 0x5d, 0xba,
989 		0x74, 0xe9, 0x52, 0xa5,
990 		0x4b, 0x96, 0x2c, 0xd8,
991 		0x31, 0xe3, 0x46, 0x8d,
992 		0x1b, 0xb7, 0x6f, 0xde,
993 		0x3d, 0xfb, 0x76, 0xed,
994 		0x5a, 0xb5, 0x6b, 0xd6,
995 		0x2d, 0xdb, 0x36, 0xec,
996 
997 	};
998 
999 	if ((index & 0x7f) == 0)
1000 		return 1;
1001 	while (ret < sizeof (fbdv_tb)) {
1002 		if (fbdv_tb[ret] == index)
1003 			break;
1004 		ret++;
1005 	}
1006 	ret++;
1007 
1008 	return ret;
1009 }
1010 
1011 #define PLL_FBK_PLL_LOCAL	0
1012 #define PLL_FBK_CPU		1
1013 #define PLL_FBK_PERCLK		5
1014 
get_sys_info(sys_info_t * sysInfo)1015 void get_sys_info (sys_info_t * sysInfo)
1016 {
1017 	unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000);
1018 	unsigned long m = 1;
1019 	unsigned int  tmp;
1020 	unsigned char fwdva[16] = {
1021 		1, 2, 14, 9, 4, 11, 16, 13,
1022 		12, 5, 6, 15, 10, 7, 8, 3,
1023 	};
1024 	unsigned char sel, cpudv0, plb2xDiv;
1025 
1026 	mfcpr(CPR0_PLLD, tmp);
1027 
1028 	/*
1029 	 * Determine forward divider A
1030 	 */
1031 	sysInfo->pllFwdDiv = fwdva[((tmp >> 16) & 0x0f)];	/* FWDVA */
1032 
1033 	/*
1034 	 * Determine FBK_DIV.
1035 	 */
1036 	sysInfo->pllFbkDiv = get_fbdv(((tmp >> 24) & 0x0ff)); /* FBDV */
1037 
1038 	/*
1039 	 * Determine PLBDV0
1040 	 */
1041 	sysInfo->pllPlbDiv = 2;
1042 
1043 	/*
1044 	 * Determine PERDV0
1045 	 */
1046 	mfcpr(CPR0_PERD, tmp);
1047 	tmp = (tmp >> 24) & 0x03;
1048 	sysInfo->pllExtBusDiv = (tmp == 0) ? 4 : tmp;
1049 
1050 	/*
1051 	 * Determine OPBDV0
1052 	 */
1053 	mfcpr(CPR0_OPBD0, tmp);
1054 	tmp = (tmp >> 24) & 0x03;
1055 	sysInfo->pllOpbDiv = (tmp == 0) ? 4 : tmp;
1056 
1057 	/* Determine PLB2XDV0 */
1058 	mfcpr(CPR0_PLBD, tmp);
1059 	tmp = (tmp >> 16) & 0x07;
1060 	plb2xDiv = (tmp == 0) ? 8 : tmp;
1061 
1062 	/* Determine CPUDV0 */
1063 	mfcpr(CPR0_CPUD, tmp);
1064 	tmp = (tmp >> 24) & 0x07;
1065 	cpudv0 = (tmp == 0) ? 8 : tmp;
1066 
1067 	/* Determine SEL(5:7) in CPR0_PLLC */
1068 	mfcpr(CPR0_PLLC, tmp);
1069 	sel = (tmp >> 24) & 0x07;
1070 
1071 	/*
1072 	 * Determine the M factor
1073 	 * PLL local: M = FBDV
1074 	 * CPU clock: M = FBDV * FWDVA * CPUDV0
1075 	 * PerClk	: M = FBDV * FWDVA * PLB2XDV0 * PLBDV0(2) * OPBDV0 * PERDV0
1076 	 *
1077 	 */
1078 	switch (sel) {
1079 	case PLL_FBK_CPU:
1080 		m = sysInfo->pllFwdDiv * cpudv0;
1081 		break;
1082 	case PLL_FBK_PERCLK:
1083 		m = sysInfo->pllFwdDiv * plb2xDiv * 2
1084 			* sysInfo->pllOpbDiv * sysInfo->pllExtBusDiv;
1085 		break;
1086 	case PLL_FBK_PLL_LOCAL:
1087 		break;
1088 	default:
1089 		printf("%s unknown m\n", __FUNCTION__);
1090 		return;
1091 
1092 	}
1093 	m *= sysInfo->pllFbkDiv;
1094 
1095 	/*
1096 	 * Determine VCO clock frequency
1097 	 */
1098 	sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) /
1099 		(unsigned long long)sysClkPeriodPs;
1100 
1101 	/*
1102 	 * Determine CPU clock frequency
1103 	 */
1104 	sysInfo->freqProcessor = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * cpudv0);
1105 
1106 	/*
1107 	 * Determine PLB clock frequency, ddr1x should be the same
1108 	 */
1109 	sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDiv * plb2xDiv * 2);
1110 	sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv;
1111 	sysInfo->freqDDR = sysInfo->freqPLB;
1112 	sysInfo->freqEBC = sysInfo->freqOPB / sysInfo->pllExtBusDiv;
1113 	sysInfo->freqUART = sysInfo->freqPLB;
1114 }
1115 
1116 #endif
1117 
get_clocks(void)1118 int get_clocks (void)
1119 {
1120 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1121     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1122     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1123     defined(CONFIG_440)
1124 	sys_info_t sys_info;
1125 
1126 	get_sys_info (&sys_info);
1127 	gd->cpu_clk = sys_info.freqProcessor;
1128 	gd->bus_clk = sys_info.freqPLB;
1129 
1130 #endif	/* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
1131 
1132 #ifdef CONFIG_IOP480
1133 	gd->cpu_clk = 66000000;
1134 	gd->bus_clk = 66000000;
1135 #endif
1136 	return (0);
1137 }
1138 
1139 
1140 /********************************************
1141  * get_bus_freq
1142  * return PLB bus freq in Hz
1143  *********************************************/
get_bus_freq(ulong dummy)1144 ulong get_bus_freq (ulong dummy)
1145 {
1146 	ulong val;
1147 
1148 #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \
1149     defined(CONFIG_405EP) || defined(CONFIG_405EZ) || \
1150     defined(CONFIG_405EX) || defined(CONFIG_405) || \
1151     defined(CONFIG_440)
1152 	sys_info_t sys_info;
1153 
1154 	get_sys_info (&sys_info);
1155 	val = sys_info.freqPLB;
1156 
1157 #elif defined(CONFIG_IOP480)
1158 
1159 	val = 66;
1160 
1161 #else
1162 # error get_bus_freq() not implemented
1163 #endif
1164 
1165 	return val;
1166 }
1167 
1168 #if !defined(CONFIG_IOP480)
get_OPB_freq(void)1169 ulong get_OPB_freq (void)
1170 {
1171 	PPC4xx_SYS_INFO sys_info;
1172 
1173 	get_sys_info (&sys_info);
1174 
1175 	return sys_info.freqOPB;
1176 }
1177 #endif
1178