]>
Commit | Line | Data |
---|---|---|
f046ccd1 EL |
1 | /* |
2 | * (C) Copyright 2000-2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
4 | * | |
5 | * Copyright 2004 Freescale Semiconductor, Inc. | |
6 | * | |
7 | * See file CREDITS for list of people who contributed to this | |
8 | * project. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
24 | * | |
25 | * Change log: | |
26 | * | |
27 | * 20050101: Eran Liberty ([email protected]) | |
28 | * Initial file creating (porting from 85XX & 8260) | |
29 | */ | |
30 | ||
31 | #include <common.h> | |
32 | #include <mpc83xx.h> | |
33 | #include <asm/processor.h> | |
34 | ||
35 | /* ----------------------------------------------------------------- */ | |
36 | ||
37 | typedef enum { | |
38 | _unk, | |
39 | _off, | |
40 | _byp, | |
41 | _x8, | |
42 | _x4, | |
43 | _x2, | |
44 | _x1, | |
45 | _1x, | |
46 | _1_5x, | |
47 | _2x, | |
48 | _2_5x, | |
49 | _3x | |
50 | } mult_t; | |
51 | ||
52 | typedef struct { | |
53 | mult_t core_csb_ratio; | |
54 | mult_t vco_divider; | |
55 | } corecnf_t; | |
56 | ||
57 | corecnf_t corecnf_tab[] = { | |
58 | { _byp, _byp}, /* 0x00 */ | |
59 | { _byp, _byp}, /* 0x01 */ | |
60 | { _byp, _byp}, /* 0x02 */ | |
61 | { _byp, _byp}, /* 0x03 */ | |
62 | { _byp, _byp}, /* 0x04 */ | |
63 | { _byp, _byp}, /* 0x05 */ | |
64 | { _byp, _byp}, /* 0x06 */ | |
65 | { _byp, _byp}, /* 0x07 */ | |
66 | { _1x, _x2}, /* 0x08 */ | |
67 | { _1x, _x4}, /* 0x09 */ | |
68 | { _1x, _x8}, /* 0x0A */ | |
69 | { _1x, _x8}, /* 0x0B */ | |
70 | {_1_5x, _x2}, /* 0x0C */ | |
71 | {_1_5x, _x4}, /* 0x0D */ | |
72 | {_1_5x, _x8}, /* 0x0E */ | |
73 | {_1_5x, _x8}, /* 0x0F */ | |
74 | { _2x, _x2}, /* 0x10 */ | |
75 | { _2x, _x4}, /* 0x11 */ | |
76 | { _2x, _x8}, /* 0x12 */ | |
77 | { _2x, _x8}, /* 0x13 */ | |
78 | {_2_5x, _x2}, /* 0x14 */ | |
79 | {_2_5x, _x4}, /* 0x15 */ | |
80 | {_2_5x, _x8}, /* 0x16 */ | |
81 | {_2_5x, _x8}, /* 0x17 */ | |
82 | { _3x, _x2}, /* 0x18 */ | |
83 | { _3x, _x4}, /* 0x19 */ | |
84 | { _3x, _x8}, /* 0x1A */ | |
85 | { _3x, _x8}, /* 0x1B */ | |
86 | }; | |
87 | ||
88 | /* ----------------------------------------------------------------- */ | |
89 | ||
90 | /* | |
91 | * | |
92 | */ | |
93 | int get_clocks (void) | |
94 | { | |
95 | DECLARE_GLOBAL_DATA_PTR; | |
96 | volatile immap_t *im = (immap_t *)CFG_IMMRBAR; | |
97 | u32 pci_sync_in; | |
98 | u8 spmf; | |
99 | u8 clkin_div; | |
100 | u32 sccr; | |
101 | u32 corecnf_tab_index; | |
102 | u8 corepll; | |
103 | u32 lcrr; | |
de1d0a69 | 104 | |
f046ccd1 EL |
105 | u32 csb_clk; |
106 | u32 tsec1_clk; | |
107 | u32 tsec2_clk; | |
108 | u32 core_clk; | |
109 | u32 usbmph_clk; | |
110 | u32 usbdr_clk; | |
111 | u32 i2c_clk; | |
112 | u32 enc_clk; | |
113 | u32 lbiu_clk; | |
114 | u32 lclk_clk; | |
115 | u32 ddr_clk; | |
de1d0a69 | 116 | |
f046ccd1 EL |
117 | if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im) |
118 | return -1; | |
de1d0a69 | 119 | |
f046ccd1 EL |
120 | #ifndef CFG_HRCW_HIGH |
121 | # error "CFG_HRCW_HIGH must be defined in include/configs/MCP83XXADS.h" | |
122 | #endif /* CFG_HCWD_HIGH */ | |
123 | ||
124 | #if (CFG_HRCW_HIGH & HRCWH_PCI_HOST) | |
125 | # ifndef CONFIG_83XX_CLKIN | |
126 | # error "In PCI Host Mode, CONFIG_83XX_CLKIN must be defined in include/configs/MCP83XXADS.h" | |
127 | # endif /* CONFIG_83XX_CLKIN */ | |
128 | # ifdef CONFIG_83XX_PCICLK | |
129 | # warning "In PCI Host Mode, CONFIG_83XX_PCICLK in include/configs/MCP83XXADS.h is igonred." | |
130 | # endif /* CONFIG_83XX_PCICLK */ | |
131 | /* PCI Host Mode */ | |
132 | if (!(im->reset.rcwh & RCWH_PCIHOST)) { | |
133 | /* though RCWH_PCIHOST is defined in CFG_HRCW_HIGH the im->reset.rcwhr PCI Host Mode is disabled */ | |
134 | /* FIXME: findout if there is a way to issue some warning */ | |
135 | return -2; | |
f046ccd1 EL |
136 | } |
137 | if (im->clk.spmr & SPMR_CKID) { | |
138 | pci_sync_in = CONFIG_83XX_CLKIN / 2; /* PCI Clock is half CONFIG_83XX_CLKIN */ | |
139 | } | |
140 | else { | |
141 | pci_sync_in = CONFIG_83XX_CLKIN; | |
142 | } | |
143 | #else | |
144 | # ifdef CONFIG_83XX_CLKIN | |
145 | # warning "In PCI Agent Mode, CONFIG_83XX_CLKIN in include/configs/MCP83XXADS.h is igonred." | |
146 | # endif /* CONFIG_83XX_CLKIN */ | |
147 | # ifndef CONFIG_83XX_PCICLK | |
148 | # error "In PCI Agent Mode, CONFIG_83XX_PCICLK must be defined in include/configs/MCP83XXADS.h" | |
149 | # endif /* CONFIG_83XX_PCICLK */ | |
150 | /* PCI Agent Mode */ | |
151 | if (im->reset.rcwh & RCWH_PCIHOST) { | |
152 | /* though RCWH_PCIHOST is not defined in CFG_HRCW_HIGH the im->reset.rcwhr PCI Host Mode is enabled */ | |
153 | return -3; | |
154 | } | |
155 | pci_sync_in = CONFIG_83XX_PCICLK; | |
156 | #endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST) */ | |
157 | ||
158 | /* we have up to date pci_sync_in */ | |
f046ccd1 EL |
159 | spmf = ((im->reset.rcwl & RCWL_SPMF) >> RCWL_SPMF_SHIFT); |
160 | clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT); | |
de1d0a69 | 161 | |
f046ccd1 EL |
162 | if ((im->reset.rcwl & RCWL_LBIUCM) || (im->reset.rcwl & RCWL_DDRCM)) { |
163 | csb_clk = (pci_sync_in * spmf * (1 + clkin_div)) / 2; | |
164 | } | |
165 | else { | |
166 | csb_clk = pci_sync_in * spmf * (1 + clkin_div); | |
167 | } | |
de1d0a69 | 168 | |
f046ccd1 EL |
169 | sccr = im->clk.sccr; |
170 | switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) { | |
171 | case 0: | |
172 | tsec1_clk = 0; | |
173 | break; | |
174 | case 1: | |
175 | tsec1_clk = csb_clk; | |
176 | break; | |
177 | case 2: | |
178 | tsec1_clk = csb_clk / 2; | |
179 | break; | |
180 | case 3: | |
181 | tsec1_clk = csb_clk / 3; | |
182 | break; | |
183 | default: | |
184 | /* unkown SCCR_TSEC1CM value */ | |
185 | return -4; | |
186 | } | |
de1d0a69 | 187 | |
f046ccd1 EL |
188 | switch ((sccr & SCCR_TSEC2CM) >> SCCR_TSEC2CM_SHIFT) { |
189 | case 0: | |
190 | tsec2_clk = 0; | |
191 | break; | |
192 | case 1: | |
193 | tsec2_clk = csb_clk; | |
194 | break; | |
195 | case 2: | |
196 | tsec2_clk = csb_clk / 2; | |
197 | break; | |
198 | case 3: | |
199 | tsec2_clk = csb_clk / 3; | |
200 | break; | |
201 | default: | |
202 | /* unkown SCCR_TSEC2CM value */ | |
203 | return -5; | |
204 | } | |
205 | i2c_clk = tsec2_clk; | |
de1d0a69 | 206 | |
f046ccd1 EL |
207 | switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) { |
208 | case 0: | |
209 | enc_clk = 0; | |
210 | break; | |
211 | case 1: | |
212 | enc_clk = csb_clk; | |
213 | break; | |
214 | case 2: | |
215 | enc_clk = csb_clk / 2; | |
216 | break; | |
217 | case 3: | |
218 | enc_clk = csb_clk / 3; | |
219 | break; | |
220 | default: | |
221 | /* unkown SCCR_ENCCM value */ | |
222 | return -6; | |
223 | } | |
de1d0a69 | 224 | |
f046ccd1 EL |
225 | switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) { |
226 | case 0: | |
227 | usbmph_clk = 0; | |
228 | break; | |
229 | case 1: | |
230 | usbmph_clk = csb_clk; | |
231 | break; | |
232 | case 2: | |
233 | usbmph_clk = csb_clk / 2; | |
234 | break; | |
235 | case 3: | |
236 | usbmph_clk = csb_clk / 3; | |
237 | break; | |
238 | default: | |
239 | /* unkown SCCR_USBMPHCM value */ | |
240 | return -7; | |
241 | } | |
242 | ||
243 | switch ((sccr & SCCR_USBDRCM) >> SCCR_USBDRCM_SHIFT) { | |
244 | case 0: | |
245 | usbdr_clk = 0; | |
246 | break; | |
247 | case 1: | |
248 | usbdr_clk = csb_clk; | |
249 | break; | |
250 | case 2: | |
251 | usbdr_clk = csb_clk / 2; | |
252 | break; | |
253 | case 3: | |
254 | usbdr_clk = csb_clk / 3; | |
255 | break; | |
256 | default: | |
257 | /* unkown SCCR_USBDRCM value */ | |
258 | return -8; | |
259 | } | |
de1d0a69 | 260 | |
f046ccd1 EL |
261 | if (usbmph_clk != 0 |
262 | && usbdr_clk != 0 | |
263 | && usbmph_clk != usbdr_clk ) { | |
264 | /* if USB MPH clock is not disabled and USB DR clock is not disabled than USB MPH & USB DR must have the same rate */ | |
265 | return -9; | |
266 | } | |
de1d0a69 | 267 | |
f046ccd1 EL |
268 | lbiu_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_LBIUCM) >> RCWL_LBIUCM_SHIFT)); |
269 | lcrr = (im->lbus.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT; | |
270 | switch (lcrr) { | |
271 | case 2: | |
272 | case 4: | |
273 | case 8: | |
274 | lclk_clk = lbiu_clk / lcrr; | |
275 | break; | |
276 | default: | |
277 | /* unknown lcrr */ | |
278 | return -10; | |
279 | } | |
de1d0a69 | 280 | |
f046ccd1 | 281 | ddr_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_DDRCM) >> RCWL_DDRCM_SHIFT)); |
de1d0a69 | 282 | |
f046ccd1 EL |
283 | corepll = (im->reset.rcwl & RCWL_COREPLL) >> RCWL_COREPLL_SHIFT; |
284 | corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60) >> 5); | |
285 | if (corecnf_tab_index > (sizeof(corecnf_tab)/sizeof(corecnf_t)) ) { | |
286 | /* corecnf_tab_index is too high, possibly worng value */ | |
287 | return -11; | |
288 | } | |
289 | switch (corecnf_tab[corecnf_tab_index].core_csb_ratio) { | |
290 | case _byp: | |
291 | case _x1: | |
292 | case _1x: | |
293 | core_clk = csb_clk; | |
294 | break; | |
295 | case _1_5x: | |
296 | core_clk = (3 * csb_clk) / 2; | |
297 | break; | |
298 | case _2x: | |
299 | core_clk = 2 * csb_clk; | |
300 | break; | |
301 | case _2_5x: | |
302 | core_clk = ( 5 * csb_clk) / 2; | |
303 | break; | |
304 | case _3x: | |
305 | core_clk = 3 * csb_clk; | |
306 | break; | |
307 | default: | |
308 | /* unkown core to csb ratio */ | |
309 | return -12; | |
310 | } | |
de1d0a69 | 311 | |
f046ccd1 EL |
312 | gd->csb_clk = csb_clk ; |
313 | gd->tsec1_clk = tsec1_clk ; | |
314 | gd->tsec2_clk = tsec2_clk ; | |
315 | gd->core_clk = core_clk ; | |
316 | gd->usbmph_clk = usbmph_clk; | |
317 | gd->usbdr_clk = usbdr_clk ; | |
318 | gd->i2c_clk = i2c_clk ; | |
de1d0a69 | 319 | gd->enc_clk = enc_clk ; |
f046ccd1 EL |
320 | gd->lbiu_clk = lbiu_clk ; |
321 | gd->lclk_clk = lclk_clk ; | |
322 | gd->ddr_clk = ddr_clk ; | |
de1d0a69 | 323 | |
f046ccd1 EL |
324 | gd->cpu_clk = gd->core_clk; |
325 | gd->bus_clk = gd->lbiu_clk; | |
326 | return 0; | |
327 | } | |
328 | ||
329 | /******************************************** | |
330 | * get_bus_freq | |
331 | * return system bus freq in Hz | |
332 | *********************************************/ | |
333 | ulong get_bus_freq (ulong dummy) | |
334 | { | |
335 | DECLARE_GLOBAL_DATA_PTR; | |
336 | return gd->csb_clk; | |
337 | } | |
338 | ||
339 | int print_clock_conf (void) | |
340 | { | |
341 | DECLARE_GLOBAL_DATA_PTR; | |
de1d0a69 | 342 | |
f046ccd1 EL |
343 | printf("Clock configuration:\n"); |
344 | printf(" Coherent System Bus: %4d MHz\n",gd->csb_clk/1000000); | |
345 | printf(" Core: %4d MHz\n",gd->core_clk/1000000); | |
346 | printf(" Local Bus Controller:%4d MHz\n",gd->lbiu_clk/1000000); | |
347 | printf(" Local Bus: %4d MHz\n",gd->lclk_clk/1000000); | |
348 | printf(" DDR: %4d MHz\n",gd->ddr_clk/1000000); | |
349 | printf(" I2C: %4d MHz\n",gd->i2c_clk/1000000); | |
350 | printf(" TSEC1: %4d MHz\n",gd->tsec1_clk/1000000); | |
351 | printf(" TSEC2: %4d MHz\n",gd->tsec2_clk/1000000); | |
352 | printf(" USB MPH: %4d MHz\n",gd->usbmph_clk/1000000); | |
353 | printf(" USB DR: %4d MHz\n",gd->usbdr_clk/1000000); | |
de1d0a69 | 354 | |
f046ccd1 EL |
355 | #if 0 |
356 | DECLARE_GLOBAL_DATA_PTR; | |
357 | ||
358 | volatile immap_t *immap = (immap_t *) CFG_IMMR; | |
359 | ulong sccr, dfbrg; | |
360 | ulong scmr, corecnf, busdf, cpmdf, plldf, pllmf; | |
361 | corecnf_t *cp; | |
362 | ||
363 | sccr = immap->im_clkrst.car_sccr; | |
364 | dfbrg = (sccr & SCCR_DFBRG_MSK) >> SCCR_DFBRG_SHIFT; | |
365 | ||
366 | scmr = immap->im_clkrst.car_scmr; | |
367 | corecnf = (scmr & SCMR_CORECNF_MSK) >> SCMR_CORECNF_SHIFT; | |
368 | busdf = (scmr & SCMR_BUSDF_MSK) >> SCMR_BUSDF_SHIFT; | |
369 | cpmdf = (scmr & SCMR_CPMDF_MSK) >> SCMR_CPMDF_SHIFT; | |
370 | plldf = (scmr & SCMR_PLLDF) ? 1 : 0; | |
371 | pllmf = (scmr & SCMR_PLLMF_MSK) >> SCMR_PLLMF_SHIFT; | |
372 | ||
373 | cp = &corecnf_tab[corecnf]; | |
374 | ||
375 | puts (CPU_ID_STR " Clock Configuration\n - Bus-to-Core Mult "); | |
376 | ||
377 | switch (cp->b2c_mult) { | |
378 | case _byp: | |
379 | puts ("BYPASS"); | |
380 | break; | |
381 | ||
382 | case _off: | |
383 | puts ("OFF"); | |
384 | break; | |
385 | ||
386 | case _unk: | |
387 | puts ("UNKNOWN"); | |
388 | break; | |
389 | ||
390 | default: | |
391 | printf ("%d%sx", | |
392 | cp->b2c_mult / 2, | |
393 | (cp->b2c_mult % 2) ? ".5" : ""); | |
394 | break; | |
395 | } | |
396 | ||
397 | printf (", VCO Div %d, 60x Bus Freq %s, Core Freq %s\n", | |
398 | cp->vco_div, cp->freq_60x, cp->freq_core); | |
399 | ||
400 | printf (" - dfbrg %ld, corecnf 0x%02lx, busdf %ld, cpmdf %ld, " | |
401 | "plldf %ld, pllmf %ld\n", dfbrg, corecnf, busdf, cpmdf, plldf, | |
402 | pllmf); | |
403 | ||
404 | printf (" - vco_out %10ld, scc_clk %10ld, brg_clk %10ld\n", | |
405 | gd->vco_out, gd->scc_clk, gd->brg_clk); | |
406 | ||
407 | printf (" - cpu_clk %10ld, cpm_clk %10ld, bus_clk %10ld\n", | |
408 | gd->cpu_clk, gd->cpm_clk, gd->bus_clk); | |
409 | ||
410 | if (sccr & SCCR_PCI_MODE) { | |
411 | uint pci_div; | |
412 | ||
413 | pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) * | |
414 | ( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1); | |
415 | ||
416 | printf (" - pci_clk %10ld\n", (gd->cpm_clk * 2) / pci_div); | |
417 | } | |
418 | putc ('\n'); | |
419 | #endif | |
de1d0a69 | 420 | return 0; |
f046ccd1 | 421 | } |