]>
Commit | Line | Data |
---|---|---|
c609719b WD |
1 | /* |
2 | * (C) Copyright 2000 | |
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 | ||
d87080b7 | 29 | DECLARE_GLOBAL_DATA_PTR; |
c609719b WD |
30 | |
31 | #define ONE_BILLION 1000000000 | |
6c5879f3 MB |
32 | #ifdef DEBUG |
33 | #define DEBUGF(fmt,args...) printf(fmt ,##args) | |
34 | #else | |
35 | #define DEBUGF(fmt,args...) | |
36 | #endif | |
c609719b WD |
37 | |
38 | #if defined(CONFIG_405GP) || defined(CONFIG_405CR) | |
39 | ||
40 | void get_sys_info (PPC405_SYS_INFO * sysInfo) | |
41 | { | |
42 | unsigned long pllmr; | |
43 | unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000); | |
44 | uint pvr = get_pvr(); | |
45 | unsigned long psr; | |
46 | unsigned long m; | |
47 | ||
48 | /* | |
49 | * Read PLL Mode register | |
50 | */ | |
51 | pllmr = mfdcr (pllmd); | |
52 | ||
53 | /* | |
54 | * Read Pin Strapping register | |
55 | */ | |
56 | psr = mfdcr (strap); | |
57 | ||
58 | /* | |
59 | * Determine FWD_DIV. | |
60 | */ | |
61 | sysInfo->pllFwdDiv = 8 - ((pllmr & PLLMR_FWD_DIV_MASK) >> 29); | |
62 | ||
63 | /* | |
64 | * Determine FBK_DIV. | |
65 | */ | |
66 | sysInfo->pllFbkDiv = ((pllmr & PLLMR_FB_DIV_MASK) >> 25); | |
67 | if (sysInfo->pllFbkDiv == 0) { | |
68 | sysInfo->pllFbkDiv = 16; | |
69 | } | |
70 | ||
71 | /* | |
72 | * Determine PLB_DIV. | |
73 | */ | |
74 | sysInfo->pllPlbDiv = ((pllmr & PLLMR_CPU_TO_PLB_MASK) >> 17) + 1; | |
75 | ||
76 | /* | |
77 | * Determine PCI_DIV. | |
78 | */ | |
79 | sysInfo->pllPciDiv = ((pllmr & PLLMR_PCI_TO_PLB_MASK) >> 13) + 1; | |
80 | ||
81 | /* | |
82 | * Determine EXTBUS_DIV. | |
83 | */ | |
84 | sysInfo->pllExtBusDiv = ((pllmr & PLLMR_EXB_TO_PLB_MASK) >> 11) + 2; | |
85 | ||
86 | /* | |
87 | * Determine OPB_DIV. | |
88 | */ | |
89 | sysInfo->pllOpbDiv = ((pllmr & PLLMR_OPB_TO_PLB_MASK) >> 15) + 1; | |
90 | ||
91 | /* | |
92 | * Check if PPC405GPr used (mask minor revision field) | |
93 | */ | |
baa3d528 | 94 | if ((pvr & 0xfffffff0) == (PVR_405GPR_RB & 0xfffffff0)) { |
c609719b WD |
95 | /* |
96 | * Determine FWD_DIV B (only PPC405GPr with new mode strapping). | |
97 | */ | |
98 | sysInfo->pllFwdDivB = 8 - (pllmr & PLLMR_FWDB_DIV_MASK); | |
99 | ||
100 | /* | |
101 | * Determine factor m depending on PLL feedback clock source | |
102 | */ | |
103 | if (!(psr & PSR_PCI_ASYNC_EN)) { | |
104 | if (psr & PSR_NEW_MODE_EN) { | |
105 | /* | |
106 | * sync pci clock used as feedback (new mode) | |
107 | */ | |
108 | m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllPciDiv; | |
109 | } else { | |
110 | /* | |
111 | * sync pci clock used as feedback (legacy mode) | |
112 | */ | |
113 | m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllPciDiv; | |
114 | } | |
115 | } else if (psr & PSR_NEW_MODE_EN) { | |
116 | if (psr & PSR_PERCLK_SYNC_MODE_EN) { | |
117 | /* | |
118 | * PerClk used as feedback (new mode) | |
119 | */ | |
120 | m = 1 * sysInfo->pllFwdDivB * 2 * sysInfo->pllExtBusDiv; | |
121 | } else { | |
122 | /* | |
123 | * CPU clock used as feedback (new mode) | |
124 | */ | |
125 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv; | |
126 | } | |
127 | } else if (sysInfo->pllExtBusDiv == sysInfo->pllFbkDiv) { | |
128 | /* | |
129 | * PerClk used as feedback (legacy mode) | |
130 | */ | |
131 | m = 1 * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv * sysInfo->pllExtBusDiv; | |
132 | } else { | |
133 | /* | |
134 | * PLB clock used as feedback (legacy mode) | |
135 | */ | |
136 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB * sysInfo->pllPlbDiv; | |
137 | } | |
138 | ||
b39392a9 SR |
139 | sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) / |
140 | (unsigned long long)sysClkPeriodPs; | |
141 | sysInfo->freqProcessor = sysInfo->freqVCOHz / sysInfo->pllFwdDiv; | |
142 | sysInfo->freqPLB = sysInfo->freqVCOHz / (sysInfo->pllFwdDivB * sysInfo->pllPlbDiv); | |
c609719b WD |
143 | } else { |
144 | /* | |
145 | * Check pllFwdDiv to see if running in bypass mode where the CPU speed | |
146 | * is equal to the 405GP SYS_CLK_FREQ. If not in bypass mode, check VCO | |
147 | * to make sure it is within the proper range. | |
148 | * spec: VCO = SYS_CLOCK x FBKDIV x PLBDIV x FWDDIV | |
149 | * Note freqVCO is calculated in Mhz to avoid errors introduced by rounding. | |
150 | */ | |
151 | if (sysInfo->pllFwdDiv == 1) { | |
152 | sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ; | |
153 | sysInfo->freqPLB = CONFIG_SYS_CLK_FREQ / sysInfo->pllPlbDiv; | |
154 | } else { | |
b39392a9 SR |
155 | sysInfo->freqVCOHz = ( 1000000000000LL * |
156 | (unsigned long long)sysInfo->pllFwdDiv * | |
157 | (unsigned long long)sysInfo->pllFbkDiv * | |
158 | (unsigned long long)sysInfo->pllPlbDiv | |
159 | ) / (unsigned long long)sysClkPeriodPs; | |
160 | sysInfo->freqPLB = (ONE_BILLION / ((sysClkPeriodPs * 10) / | |
161 | sysInfo->pllFbkDiv)) * 10000; | |
162 | sysInfo->freqProcessor = sysInfo->freqPLB * sysInfo->pllPlbDiv; | |
c609719b WD |
163 | } |
164 | } | |
165 | } | |
166 | ||
167 | ||
168 | /******************************************** | |
169 | * get_OPB_freq | |
170 | * return OPB bus freq in Hz | |
171 | *********************************************/ | |
172 | ulong get_OPB_freq (void) | |
173 | { | |
174 | ulong val = 0; | |
175 | ||
176 | PPC405_SYS_INFO sys_info; | |
177 | ||
178 | get_sys_info (&sys_info); | |
179 | val = sys_info.freqPLB / sys_info.pllOpbDiv; | |
180 | ||
181 | return val; | |
182 | } | |
183 | ||
184 | ||
185 | /******************************************** | |
186 | * get_PCI_freq | |
187 | * return PCI bus freq in Hz | |
188 | *********************************************/ | |
189 | ulong get_PCI_freq (void) | |
190 | { | |
191 | ulong val; | |
192 | PPC405_SYS_INFO sys_info; | |
193 | ||
194 | get_sys_info (&sys_info); | |
195 | val = sys_info.freqPLB / sys_info.pllPciDiv; | |
196 | return val; | |
197 | } | |
198 | ||
199 | ||
200 | #elif defined(CONFIG_440) | |
c157d8e2 | 201 | |
887e2ec9 SR |
202 | #if defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ |
203 | defined(CONFIG_440EPX) || defined(CONFIG_440GRX) | |
c157d8e2 SR |
204 | void get_sys_info (sys_info_t *sysInfo) |
205 | { | |
206 | unsigned long temp; | |
207 | unsigned long reg; | |
208 | unsigned long lfdiv; | |
209 | unsigned long m; | |
210 | unsigned long prbdv0; | |
211 | /* | |
212 | WARNING: ASSUMES the following: | |
213 | ENG=1 | |
214 | PRADV0=1 | |
215 | PRBDV0=1 | |
216 | */ | |
217 | ||
218 | /* Decode CPR0_PLLD0 for divisors */ | |
219 | mfclk(clk_plld, reg); | |
220 | temp = (reg & PLLD_FWDVA_MASK) >> 16; | |
221 | sysInfo->pllFwdDivA = temp ? temp : 16; | |
222 | temp = (reg & PLLD_FWDVB_MASK) >> 8; | |
223 | sysInfo->pllFwdDivB = temp ? temp: 8 ; | |
224 | temp = (reg & PLLD_FBDV_MASK) >> 24; | |
225 | sysInfo->pllFbkDiv = temp ? temp : 32; | |
226 | lfdiv = reg & PLLD_LFBDV_MASK; | |
227 | ||
228 | mfclk(clk_opbd, reg); | |
229 | temp = (reg & OPBDDV_MASK) >> 24; | |
230 | sysInfo->pllOpbDiv = temp ? temp : 4; | |
231 | ||
232 | mfclk(clk_perd, reg); | |
233 | temp = (reg & PERDV_MASK) >> 24; | |
234 | sysInfo->pllExtBusDiv = temp ? temp : 8; | |
235 | ||
236 | mfclk(clk_primbd, reg); | |
237 | temp = (reg & PRBDV_MASK) >> 24; | |
238 | prbdv0 = temp ? temp : 8; | |
239 | ||
240 | mfclk(clk_spcid, reg); | |
241 | temp = (reg & SPCID_MASK) >> 24; | |
242 | sysInfo->pllPciDiv = temp ? temp : 4; | |
243 | ||
244 | /* Calculate 'M' based on feedback source */ | |
245 | mfsdr(sdr_sdstp0, reg); | |
246 | temp = (reg & PLLSYS0_SEL_MASK) >> 27; | |
247 | if (temp == 0) { /* PLL output */ | |
248 | /* Figure which pll to use */ | |
249 | mfclk(clk_pllc, reg); | |
250 | temp = (reg & PLLC_SRC_MASK) >> 29; | |
251 | if (!temp) /* PLLOUTA */ | |
252 | m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA; | |
253 | else /* PLLOUTB */ | |
254 | m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB; | |
255 | } | |
256 | else if (temp == 1) /* CPU output */ | |
257 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA; | |
258 | else /* PerClk */ | |
259 | m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB; | |
260 | ||
261 | /* Now calculate the individual clocks */ | |
262 | sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1); | |
263 | sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; | |
264 | sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0; | |
265 | sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; | |
266 | sysInfo->freqEPB = sysInfo->freqPLB/sysInfo->pllExtBusDiv; | |
267 | sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv; | |
268 | ||
269 | /* Figure which timer source to use */ | |
270 | if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */ | |
271 | temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */ | |
272 | if (CONFIG_SYS_CLK_FREQ > temp) | |
273 | sysInfo->freqTmrClk = temp; | |
274 | else | |
275 | sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ; | |
276 | } | |
277 | else /* Internal clock */ | |
278 | sysInfo->freqTmrClk = sysInfo->freqProcessor; | |
279 | } | |
280 | /******************************************** | |
281 | * get_PCI_freq | |
282 | * return PCI bus freq in Hz | |
283 | *********************************************/ | |
284 | ulong get_PCI_freq (void) | |
285 | { | |
286 | sys_info_t sys_info; | |
287 | get_sys_info (&sys_info); | |
288 | return sys_info.freqPCI; | |
289 | } | |
290 | ||
6c5879f3 | 291 | #elif !defined(CONFIG_440GX) && !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) |
c609719b WD |
292 | void get_sys_info (sys_info_t * sysInfo) |
293 | { | |
294 | unsigned long strp0; | |
295 | unsigned long temp; | |
296 | unsigned long m; | |
297 | ||
298 | /* Extract configured divisors */ | |
299 | strp0 = mfdcr( cpc0_strp0 ); | |
300 | sysInfo->pllFwdDivA = 8 - ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 15); | |
301 | sysInfo->pllFwdDivB = 8 - ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 12); | |
302 | temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 18; | |
303 | sysInfo->pllFbkDiv = temp ? temp : 16; | |
304 | sysInfo->pllOpbDiv = 1 + ((strp0 & PLLSYS0_OPB_DIV_MASK) >> 10); | |
305 | sysInfo->pllExtBusDiv = 1 + ((strp0 & PLLSYS0_EPB_DIV_MASK) >> 8); | |
306 | ||
307 | /* Calculate 'M' based on feedback source */ | |
308 | if( strp0 & PLLSYS0_EXTSL_MASK ) | |
309 | m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB; | |
310 | else | |
311 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA; | |
312 | ||
313 | /* Now calculate the individual clocks */ | |
314 | sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1); | |
315 | sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; | |
316 | sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB; | |
c157d8e2 SR |
317 | if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */ |
318 | sysInfo->freqPLB >>= 1; | |
c609719b WD |
319 | sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; |
320 | sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv; | |
321 | ||
322 | } | |
ba56f625 WD |
323 | #else |
324 | void get_sys_info (sys_info_t * sysInfo) | |
325 | { | |
326 | unsigned long strp0; | |
327 | unsigned long strp1; | |
328 | unsigned long temp; | |
329 | unsigned long temp1; | |
330 | unsigned long lfdiv; | |
331 | unsigned long m; | |
42dfe7a1 | 332 | unsigned long prbdv0; |
ba56f625 | 333 | |
4745acaa | 334 | #if defined(CONFIG_YUCCA) |
6c5879f3 MB |
335 | unsigned long sys_freq; |
336 | unsigned long sys_per=0; | |
337 | unsigned long msr; | |
338 | unsigned long pci_clock_per; | |
339 | unsigned long sdr_ddrpll; | |
340 | ||
341 | /*-------------------------------------------------------------------------+ | |
342 | | Get the system clock period. | |
343 | +-------------------------------------------------------------------------*/ | |
344 | sys_per = determine_sysper(); | |
345 | ||
346 | msr = (mfmsr () & ~(MSR_EE)); /* disable interrupts */ | |
347 | ||
348 | /*-------------------------------------------------------------------------+ | |
349 | | Calculate the system clock speed from the period. | |
350 | +-------------------------------------------------------------------------*/ | |
4745acaa | 351 | sys_freq = (ONE_BILLION / sys_per) * 1000; |
6c5879f3 MB |
352 | #endif |
353 | ||
ba56f625 WD |
354 | /* Extract configured divisors */ |
355 | mfsdr( sdr_sdstp0,strp0 ); | |
356 | mfsdr( sdr_sdstp1,strp1 ); | |
357 | ||
358 | temp = ((strp0 & PLLSYS0_FWD_DIV_A_MASK) >> 8); | |
359 | sysInfo->pllFwdDivA = temp ? temp : 16 ; | |
360 | temp = ((strp0 & PLLSYS0_FWD_DIV_B_MASK) >> 5); | |
361 | sysInfo->pllFwdDivB = temp ? temp: 8 ; | |
362 | temp = (strp0 & PLLSYS0_FB_DIV_MASK) >> 12; | |
363 | sysInfo->pllFbkDiv = temp ? temp : 32; | |
364 | temp = (strp0 & PLLSYS0_OPB_DIV_MASK); | |
365 | sysInfo->pllOpbDiv = temp ? temp : 4; | |
366 | temp = (strp1 & PLLSYS1_PERCLK_DIV_MASK) >> 24; | |
367 | sysInfo->pllExtBusDiv = temp ? temp : 4; | |
0e6d798c | 368 | prbdv0 = (strp0 >> 2) & 0x7; |
ba56f625 WD |
369 | |
370 | /* Calculate 'M' based on feedback source */ | |
371 | temp = (strp0 & PLLSYS0_SEL_MASK) >> 27; | |
372 | temp1 = (strp1 & PLLSYS1_LF_DIV_MASK) >> 26; | |
373 | lfdiv = temp1 ? temp1 : 64; | |
374 | if (temp == 0) { /* PLL output */ | |
375 | /* Figure which pll to use */ | |
376 | temp = (strp0 & PLLSYS0_SRC_MASK) >> 30; | |
377 | if (!temp) | |
378 | m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA; | |
379 | else | |
380 | m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB; | |
381 | } | |
382 | else if (temp == 1) /* CPU output */ | |
383 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA; | |
384 | else /* PerClk */ | |
385 | m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB; | |
386 | ||
387 | /* Now calculate the individual clocks */ | |
4745acaa | 388 | #if defined(CONFIG_YUCCA) |
6c5879f3 MB |
389 | sysInfo->freqVCOMhz = (m * sys_freq) ; |
390 | #else | |
4745acaa | 391 | sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m >> 1); |
6c5879f3 | 392 | #endif |
ba56f625 | 393 | sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; |
0e6d798c | 394 | sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0; |
ba56f625 WD |
395 | sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; |
396 | sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv; | |
397 | ||
4745acaa | 398 | #if defined(CONFIG_YUCCA) |
6c5879f3 MB |
399 | /* Determine PCI Clock Period */ |
400 | pci_clock_per = determine_pci_clock_per(); | |
401 | sysInfo->freqPCI = (ONE_BILLION/pci_clock_per) * 1000; | |
402 | mfsdr(sdr_ddr0, sdr_ddrpll); | |
403 | sysInfo->freqDDR = ((sysInfo->freqPLB) * SDR0_DDR0_DDRM_DECODE(sdr_ddrpll)); | |
404 | #endif | |
405 | ||
406 | ||
407 | } | |
408 | ||
409 | #endif | |
410 | ||
4745acaa | 411 | #if defined(CONFIG_YUCCA) |
6c5879f3 MB |
412 | unsigned long determine_sysper(void) |
413 | { | |
414 | unsigned int fpga_clocking_reg; | |
415 | unsigned int master_clock_selection; | |
416 | unsigned long master_clock_per = 0; | |
417 | unsigned long fb_div_selection; | |
418 | unsigned int vco_div_reg_value; | |
419 | unsigned long vco_div_selection; | |
420 | unsigned long sys_per = 0; | |
421 | int extClkVal; | |
422 | ||
423 | /*-------------------------------------------------------------------------+ | |
424 | | Read FPGA reg 0 and reg 1 to get FPGA reg information | |
425 | +-------------------------------------------------------------------------*/ | |
426 | fpga_clocking_reg = in16(FPGA_REG16); | |
427 | ||
428 | ||
429 | /* Determine Master Clock Source Selection */ | |
430 | master_clock_selection = fpga_clocking_reg & FPGA_REG16_MASTER_CLK_MASK; | |
431 | ||
432 | switch(master_clock_selection) { | |
433 | case FPGA_REG16_MASTER_CLK_66_66: | |
434 | master_clock_per = PERIOD_66_66MHZ; | |
435 | break; | |
436 | case FPGA_REG16_MASTER_CLK_50: | |
437 | master_clock_per = PERIOD_50_00MHZ; | |
438 | break; | |
439 | case FPGA_REG16_MASTER_CLK_33_33: | |
440 | master_clock_per = PERIOD_33_33MHZ; | |
441 | break; | |
442 | case FPGA_REG16_MASTER_CLK_25: | |
443 | master_clock_per = PERIOD_25_00MHZ; | |
444 | break; | |
445 | case FPGA_REG16_MASTER_CLK_EXT: | |
446 | if ((extClkVal==EXTCLK_33_33) | |
447 | && (extClkVal==EXTCLK_50) | |
448 | && (extClkVal==EXTCLK_66_66) | |
449 | && (extClkVal==EXTCLK_83)) { | |
450 | /* calculate master clock period from external clock value */ | |
451 | master_clock_per=(ONE_BILLION/extClkVal) * 1000; | |
452 | } else { | |
453 | /* Unsupported */ | |
454 | DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__); | |
455 | hang(); | |
456 | } | |
457 | break; | |
458 | default: | |
459 | /* Unsupported */ | |
460 | DEBUGF ("%s[%d] *** master clock selection failed ***\n", __FUNCTION__,__LINE__); | |
461 | hang(); | |
462 | break; | |
463 | } | |
464 | ||
465 | /* Determine FB divisors values */ | |
466 | if ((fpga_clocking_reg & FPGA_REG16_FB1_DIV_MASK) == FPGA_REG16_FB1_DIV_LOW) { | |
467 | if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW) | |
468 | fb_div_selection = FPGA_FB_DIV_6; | |
469 | else | |
470 | fb_div_selection = FPGA_FB_DIV_12; | |
471 | } else { | |
472 | if ((fpga_clocking_reg & FPGA_REG16_FB2_DIV_MASK) == FPGA_REG16_FB2_DIV_LOW) | |
473 | fb_div_selection = FPGA_FB_DIV_10; | |
474 | else | |
475 | fb_div_selection = FPGA_FB_DIV_20; | |
476 | } | |
477 | ||
478 | /* Determine VCO divisors values */ | |
479 | vco_div_reg_value = fpga_clocking_reg & FPGA_REG16_VCO_DIV_MASK; | |
480 | ||
481 | switch(vco_div_reg_value) { | |
482 | case FPGA_REG16_VCO_DIV_4: | |
483 | vco_div_selection = FPGA_VCO_DIV_4; | |
484 | break; | |
485 | case FPGA_REG16_VCO_DIV_6: | |
486 | vco_div_selection = FPGA_VCO_DIV_6; | |
487 | break; | |
488 | case FPGA_REG16_VCO_DIV_8: | |
489 | vco_div_selection = FPGA_VCO_DIV_8; | |
490 | break; | |
491 | case FPGA_REG16_VCO_DIV_10: | |
492 | default: | |
493 | vco_div_selection = FPGA_VCO_DIV_10; | |
494 | break; | |
495 | } | |
496 | ||
497 | if (master_clock_selection == FPGA_REG16_MASTER_CLK_EXT) { | |
498 | switch(master_clock_per) { | |
499 | case PERIOD_25_00MHZ: | |
500 | if (fb_div_selection == FPGA_FB_DIV_12) { | |
501 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
502 | sys_per = PERIOD_75_00MHZ; | |
503 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
504 | sys_per = PERIOD_50_00MHZ; | |
505 | } | |
506 | break; | |
507 | case PERIOD_33_33MHZ: | |
508 | if (fb_div_selection == FPGA_FB_DIV_6) { | |
509 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
510 | sys_per = PERIOD_50_00MHZ; | |
511 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
512 | sys_per = PERIOD_33_33MHZ; | |
513 | } | |
514 | if (fb_div_selection == FPGA_FB_DIV_10) { | |
515 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
516 | sys_per = PERIOD_83_33MHZ; | |
517 | if (vco_div_selection == FPGA_VCO_DIV_10) | |
518 | sys_per = PERIOD_33_33MHZ; | |
519 | } | |
520 | if (fb_div_selection == FPGA_FB_DIV_12) { | |
521 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
522 | sys_per = PERIOD_100_00MHZ; | |
523 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
524 | sys_per = PERIOD_66_66MHZ; | |
525 | if (vco_div_selection == FPGA_VCO_DIV_8) | |
526 | sys_per = PERIOD_50_00MHZ; | |
527 | } | |
528 | break; | |
529 | case PERIOD_50_00MHZ: | |
530 | if (fb_div_selection == FPGA_FB_DIV_6) { | |
531 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
532 | sys_per = PERIOD_75_00MHZ; | |
533 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
534 | sys_per = PERIOD_50_00MHZ; | |
535 | } | |
536 | if (fb_div_selection == FPGA_FB_DIV_10) { | |
537 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
538 | sys_per = PERIOD_83_33MHZ; | |
539 | if (vco_div_selection == FPGA_VCO_DIV_10) | |
540 | sys_per = PERIOD_50_00MHZ; | |
541 | } | |
542 | if (fb_div_selection == FPGA_FB_DIV_12) { | |
543 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
544 | sys_per = PERIOD_100_00MHZ; | |
545 | if (vco_div_selection == FPGA_VCO_DIV_8) | |
546 | sys_per = PERIOD_75_00MHZ; | |
547 | } | |
548 | break; | |
549 | case PERIOD_66_66MHZ: | |
550 | if (fb_div_selection == FPGA_FB_DIV_6) { | |
551 | if (vco_div_selection == FPGA_VCO_DIV_4) | |
552 | sys_per = PERIOD_100_00MHZ; | |
553 | if (vco_div_selection == FPGA_VCO_DIV_6) | |
554 | sys_per = PERIOD_66_66MHZ; | |
555 | if (vco_div_selection == FPGA_VCO_DIV_8) | |
556 | sys_per = PERIOD_50_00MHZ; | |
557 | } | |
558 | if (fb_div_selection == FPGA_FB_DIV_10) { | |
559 | if (vco_div_selection == FPGA_VCO_DIV_8) | |
560 | sys_per = PERIOD_83_33MHZ; | |
561 | if (vco_div_selection == FPGA_VCO_DIV_10) | |
562 | sys_per = PERIOD_66_66MHZ; | |
563 | } | |
564 | if (fb_div_selection == FPGA_FB_DIV_12) { | |
565 | if (vco_div_selection == FPGA_VCO_DIV_8) | |
566 | sys_per = PERIOD_100_00MHZ; | |
567 | } | |
568 | break; | |
569 | default: | |
570 | break; | |
571 | } | |
572 | ||
573 | if (sys_per == 0) { | |
574 | /* Other combinations are not supported */ | |
575 | DEBUGF ("%s[%d] *** sys period compute failed ***\n", __FUNCTION__,__LINE__); | |
576 | hang(); | |
577 | } | |
578 | } else { | |
579 | /* calcul system clock without cheking */ | |
580 | /* if engineering option clock no check is selected */ | |
581 | /* sys_per = master_clock_per * vco_div_selection / fb_div_selection */ | |
582 | sys_per = (master_clock_per/fb_div_selection) * vco_div_selection; | |
583 | } | |
584 | ||
585 | return(sys_per); | |
6c5879f3 MB |
586 | } |
587 | ||
588 | /*-------------------------------------------------------------------------+ | |
589 | | determine_pci_clock_per. | |
590 | +-------------------------------------------------------------------------*/ | |
591 | unsigned long determine_pci_clock_per(void) | |
592 | { | |
593 | unsigned long pci_clock_selection, pci_period; | |
594 | ||
595 | /*-------------------------------------------------------------------------+ | |
596 | | Read FPGA reg 6 to get PCI 0 FPGA reg information | |
597 | +-------------------------------------------------------------------------*/ | |
598 | pci_clock_selection = in16(FPGA_REG16); /* was reg6 averifier */ | |
599 | ||
600 | ||
601 | pci_clock_selection = pci_clock_selection & FPGA_REG16_PCI0_CLK_MASK; | |
602 | ||
603 | switch (pci_clock_selection) { | |
604 | case FPGA_REG16_PCI0_CLK_133_33: | |
605 | pci_period = PERIOD_133_33MHZ; | |
606 | break; | |
607 | case FPGA_REG16_PCI0_CLK_100: | |
608 | pci_period = PERIOD_100_00MHZ; | |
609 | break; | |
610 | case FPGA_REG16_PCI0_CLK_66_66: | |
611 | pci_period = PERIOD_66_66MHZ; | |
612 | break; | |
613 | default: | |
614 | pci_period = PERIOD_33_33MHZ;; | |
615 | break; | |
616 | } | |
617 | ||
618 | return(pci_period); | |
ba56f625 WD |
619 | } |
620 | #endif | |
c609719b WD |
621 | |
622 | ulong get_OPB_freq (void) | |
623 | { | |
624 | ||
625 | sys_info_t sys_info; | |
626 | get_sys_info (&sys_info); | |
627 | return sys_info.freqOPB; | |
628 | } | |
629 | ||
028ab6b5 WD |
630 | #elif defined(CONFIG_XILINX_ML300) |
631 | extern void get_sys_info (sys_info_t * sysInfo); | |
632 | extern ulong get_PCI_freq (void); | |
633 | ||
7521af1c WD |
634 | #elif defined(CONFIG_AP1000) |
635 | void get_sys_info (sys_info_t * sysInfo) { | |
636 | sysInfo->freqProcessor = 240 * 1000 * 1000; | |
637 | sysInfo->freqPLB = 80 * 1000 * 1000; | |
638 | sysInfo->freqPCI = 33 * 1000 * 1000; | |
639 | } | |
640 | ||
c609719b WD |
641 | #elif defined(CONFIG_405) |
642 | ||
643 | void get_sys_info (sys_info_t * sysInfo) { | |
644 | ||
645 | sysInfo->freqVCOMhz=3125000; | |
646 | sysInfo->freqProcessor=12*1000*1000; | |
647 | sysInfo->freqPLB=50*1000*1000; | |
648 | sysInfo->freqPCI=66*1000*1000; | |
649 | ||
650 | } | |
651 | ||
b867d705 SR |
652 | #elif defined(CONFIG_405EP) |
653 | void get_sys_info (PPC405_SYS_INFO * sysInfo) | |
654 | { | |
655 | unsigned long pllmr0; | |
656 | unsigned long pllmr1; | |
657 | unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ / 1000); | |
658 | unsigned long m; | |
659 | unsigned long pllmr0_ccdv; | |
660 | ||
661 | /* | |
662 | * Read PLL Mode registers | |
663 | */ | |
664 | pllmr0 = mfdcr (cpc0_pllmr0); | |
665 | pllmr1 = mfdcr (cpc0_pllmr1); | |
666 | ||
667 | /* | |
668 | * Determine forward divider A | |
669 | */ | |
670 | sysInfo->pllFwdDiv = 8 - ((pllmr1 & PLLMR1_FWDVA_MASK) >> 16); | |
671 | ||
672 | /* | |
673 | * Determine forward divider B (should be equal to A) | |
674 | */ | |
675 | sysInfo->pllFwdDivB = 8 - ((pllmr1 & PLLMR1_FWDVB_MASK) >> 12); | |
676 | ||
677 | /* | |
678 | * Determine FBK_DIV. | |
679 | */ | |
680 | sysInfo->pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20); | |
681 | if (sysInfo->pllFbkDiv == 0) { | |
682 | sysInfo->pllFbkDiv = 16; | |
683 | } | |
684 | ||
685 | /* | |
686 | * Determine PLB_DIV. | |
687 | */ | |
688 | sysInfo->pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1; | |
689 | ||
690 | /* | |
691 | * Determine PCI_DIV. | |
692 | */ | |
693 | sysInfo->pllPciDiv = (pllmr0 & PLLMR0_PCI_TO_PLB_MASK) + 1; | |
694 | ||
695 | /* | |
696 | * Determine EXTBUS_DIV. | |
697 | */ | |
698 | sysInfo->pllExtBusDiv = ((pllmr0 & PLLMR0_EXB_TO_PLB_MASK) >> 8) + 2; | |
699 | ||
700 | /* | |
701 | * Determine OPB_DIV. | |
702 | */ | |
703 | sysInfo->pllOpbDiv = ((pllmr0 & PLLMR0_OPB_TO_PLB_MASK) >> 12) + 1; | |
704 | ||
705 | /* | |
706 | * Determine the M factor | |
707 | */ | |
708 | m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB; | |
709 | ||
710 | /* | |
711 | * Determine VCO clock frequency | |
712 | */ | |
b39392a9 SR |
713 | sysInfo->freqVCOHz = (1000000000000LL * (unsigned long long)m) / |
714 | (unsigned long long)sysClkPeriodPs; | |
b867d705 SR |
715 | |
716 | /* | |
717 | * Determine CPU clock frequency | |
718 | */ | |
719 | pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1; | |
720 | if (pllmr1 & PLLMR1_SSCS_MASK) { | |
e55ca7e2 WD |
721 | /* |
722 | * This is true if FWDVA == FWDVB: | |
723 | * sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) | |
724 | * / pllmr0_ccdv; | |
725 | */ | |
726 | sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv * sysInfo->pllFwdDivB) | |
727 | / sysInfo->pllFwdDiv / pllmr0_ccdv; | |
b867d705 SR |
728 | } else { |
729 | sysInfo->freqProcessor = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv; | |
730 | } | |
731 | ||
732 | /* | |
733 | * Determine PLB clock frequency | |
734 | */ | |
735 | sysInfo->freqPLB = sysInfo->freqProcessor / sysInfo->pllPlbDiv; | |
b867d705 SR |
736 | } |
737 | ||
738 | ||
739 | /******************************************** | |
740 | * get_OPB_freq | |
741 | * return OPB bus freq in Hz | |
742 | *********************************************/ | |
743 | ulong get_OPB_freq (void) | |
744 | { | |
745 | ulong val = 0; | |
746 | ||
747 | PPC405_SYS_INFO sys_info; | |
748 | ||
749 | get_sys_info (&sys_info); | |
750 | val = sys_info.freqPLB / sys_info.pllOpbDiv; | |
751 | ||
752 | return val; | |
753 | } | |
754 | ||
755 | ||
756 | /******************************************** | |
757 | * get_PCI_freq | |
758 | * return PCI bus freq in Hz | |
759 | *********************************************/ | |
760 | ulong get_PCI_freq (void) | |
761 | { | |
762 | ulong val; | |
763 | PPC405_SYS_INFO sys_info; | |
764 | ||
765 | get_sys_info (&sys_info); | |
766 | val = sys_info.freqPLB / sys_info.pllPciDiv; | |
767 | return val; | |
768 | } | |
769 | ||
c609719b WD |
770 | #endif |
771 | ||
772 | int get_clocks (void) | |
773 | { | |
b867d705 | 774 | #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405) || defined(CONFIG_405EP) |
c609719b WD |
775 | sys_info_t sys_info; |
776 | ||
777 | get_sys_info (&sys_info); | |
778 | gd->cpu_clk = sys_info.freqProcessor; | |
779 | gd->bus_clk = sys_info.freqPLB; | |
780 | ||
781 | #endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */ | |
782 | ||
783 | #ifdef CONFIG_IOP480 | |
c609719b WD |
784 | gd->cpu_clk = 66000000; |
785 | gd->bus_clk = 66000000; | |
786 | #endif | |
787 | return (0); | |
788 | } | |
789 | ||
790 | ||
791 | /******************************************** | |
792 | * get_bus_freq | |
793 | * return PLB bus freq in Hz | |
794 | *********************************************/ | |
795 | ulong get_bus_freq (ulong dummy) | |
796 | { | |
797 | ulong val; | |
798 | ||
b867d705 | 799 | #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405) || defined(CONFIG_440) || defined(CONFIG_405EP) |
c609719b WD |
800 | sys_info_t sys_info; |
801 | ||
802 | get_sys_info (&sys_info); | |
803 | val = sys_info.freqPLB; | |
804 | ||
805 | #elif defined(CONFIG_IOP480) | |
806 | ||
807 | val = 66; | |
808 | ||
809 | #else | |
810 | # error get_bus_freq() not implemented | |
811 | #endif | |
812 | ||
813 | return val; | |
814 | } |