]>
Commit | Line | Data |
---|---|---|
907208c4 CL |
1 | /* |
2 | * (C) Copyright 2000-2002 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | /* | |
9 | * m8xx.c | |
10 | * | |
11 | * CPU specific code | |
12 | * | |
13 | * written or collected and sometimes rewritten by | |
14 | * Magnus Damm <damm@bitsmart.com> | |
15 | * | |
16 | * minor modifications by | |
17 | * Wolfgang Denk <wd@denx.de> | |
18 | */ | |
19 | ||
20 | #include <common.h> | |
21 | #include <watchdog.h> | |
22 | #include <command.h> | |
23 | #include <mpc8xx.h> | |
24 | #include <commproc.h> | |
25 | #include <netdev.h> | |
26 | #include <asm/cache.h> | |
27 | #include <linux/compiler.h> | |
28 | #include <asm/io.h> | |
29 | ||
30 | #if defined(CONFIG_OF_LIBFDT) | |
31 | #include <libfdt.h> | |
32 | #include <fdt_support.h> | |
33 | #endif | |
34 | ||
35 | DECLARE_GLOBAL_DATA_PTR; | |
36 | ||
37 | static char *cpu_warning = "\n " \ | |
38 | "*** Warning: CPU Core has Silicon Bugs -- Check the Errata ***"; | |
39 | ||
70fd0710 | 40 | static int check_CPU(long clock, uint pvr, uint immr) |
907208c4 CL |
41 | { |
42 | char *id_str = | |
43 | NULL; | |
ba3da734 | 44 | immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); |
907208c4 CL |
45 | uint k, m; |
46 | char buf[32]; | |
47 | char pre = 'X'; | |
48 | char *mid = "xx"; | |
49 | char *suf; | |
50 | ||
51 | /* the highest 16 bits should be 0x0050 for a 860 */ | |
52 | ||
53 | if ((pvr >> 16) != 0x0050) | |
54 | return -1; | |
55 | ||
56 | k = (immr << 16) | | |
ba3da734 | 57 | in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]); |
907208c4 CL |
58 | m = 0; |
59 | suf = ""; | |
60 | ||
61 | /* | |
62 | * Some boards use sockets so different CPUs can be used. | |
63 | * We have to check chip version in run time. | |
64 | */ | |
65 | switch (k) { | |
66 | /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */ | |
67 | case 0x08010004: /* Rev. A.0 */ | |
68 | suf = "A"; | |
69 | /* fall through */ | |
70 | case 0x08000003: /* Rev. 0.3 */ | |
71 | pre = 'M'; m = 1; | |
72 | if (id_str == NULL) | |
73 | id_str = | |
74 | "PC866x"; /* Unknown chip from MPC866 family */ | |
75 | break; | |
70fd0710 CL |
76 | case 0x09000000: |
77 | pre = 'M'; mid = suf = ""; m = 1; | |
907208c4 CL |
78 | if (id_str == NULL) |
79 | id_str = "PC885"; /* 870/875/880/885 */ | |
80 | break; | |
81 | ||
70fd0710 CL |
82 | default: |
83 | suf = NULL; | |
84 | break; | |
907208c4 CL |
85 | } |
86 | ||
87 | if (id_str == NULL) | |
88 | id_str = "PC86x"; /* Unknown 86x chip */ | |
89 | if (suf) | |
70fd0710 | 90 | printf("%c%s%sZPnn%s", pre, id_str, mid, suf); |
907208c4 | 91 | else |
70fd0710 | 92 | printf("unknown M%s (0x%08x)", id_str, k); |
907208c4 | 93 | |
70fd0710 | 94 | printf(" at %s MHz: ", strmhz(buf, clock)); |
907208c4 CL |
95 | |
96 | print_size(checkicache(), " I-Cache "); | |
97 | print_size(checkdcache(), " D-Cache"); | |
98 | ||
99 | /* do we have a FEC (860T/P or 852/859/866/885)? */ | |
100 | ||
ba3da734 CL |
101 | out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678); |
102 | if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678) | |
70fd0710 | 103 | printf(" FEC present"); |
907208c4 | 104 | |
70fd0710 CL |
105 | if (!m) |
106 | puts(cpu_warning); | |
907208c4 | 107 | |
70fd0710 | 108 | putc('\n'); |
907208c4 CL |
109 | |
110 | return 0; | |
111 | } | |
112 | ||
113 | /* ------------------------------------------------------------------------- */ | |
114 | ||
70fd0710 | 115 | int checkcpu(void) |
907208c4 CL |
116 | { |
117 | ulong clock = gd->cpu_clk; | |
70fd0710 CL |
118 | uint immr = get_immr(0); /* Return full IMMR contents */ |
119 | uint pvr = get_pvr(); | |
907208c4 | 120 | |
70fd0710 | 121 | puts("CPU: "); |
907208c4 | 122 | |
70fd0710 | 123 | return check_CPU(clock, pvr, immr); |
907208c4 CL |
124 | } |
125 | ||
126 | /* ------------------------------------------------------------------------- */ | |
127 | /* L1 i-cache */ | |
128 | ||
70fd0710 | 129 | int checkicache(void) |
907208c4 | 130 | { |
ba3da734 CL |
131 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
132 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
70fd0710 | 133 | u32 cacheon = rd_ic_cst() & IDC_ENABLED; |
ba3da734 CL |
134 | /* probe in flash memoryarea */ |
135 | u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; | |
907208c4 CL |
136 | u32 m; |
137 | u32 lines = -1; | |
138 | ||
70fd0710 CL |
139 | wr_ic_cst(IDC_UNALL); |
140 | wr_ic_cst(IDC_INVALL); | |
141 | wr_ic_cst(IDC_DISABLE); | |
907208c4 CL |
142 | __asm__ volatile ("isync"); |
143 | ||
70fd0710 CL |
144 | while (!((m = rd_ic_cst()) & IDC_CERR2)) { |
145 | wr_ic_adr(k); | |
146 | wr_ic_cst(IDC_LDLCK); | |
907208c4 CL |
147 | __asm__ volatile ("isync"); |
148 | ||
149 | lines++; | |
70fd0710 | 150 | k += 0x10; /* the number of bytes in a cacheline */ |
907208c4 CL |
151 | } |
152 | ||
70fd0710 CL |
153 | wr_ic_cst(IDC_UNALL); |
154 | wr_ic_cst(IDC_INVALL); | |
907208c4 CL |
155 | |
156 | if (cacheon) | |
70fd0710 | 157 | wr_ic_cst(IDC_ENABLE); |
907208c4 | 158 | else |
70fd0710 | 159 | wr_ic_cst(IDC_DISABLE); |
907208c4 CL |
160 | |
161 | __asm__ volatile ("isync"); | |
162 | ||
163 | return lines << 4; | |
164 | }; | |
165 | ||
166 | /* ------------------------------------------------------------------------- */ | |
167 | /* L1 d-cache */ | |
168 | /* call with cache disabled */ | |
169 | ||
70fd0710 | 170 | int checkdcache(void) |
907208c4 | 171 | { |
ba3da734 CL |
172 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
173 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
70fd0710 | 174 | u32 cacheon = rd_dc_cst() & IDC_ENABLED; |
ba3da734 CL |
175 | /* probe in flash memoryarea */ |
176 | u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; | |
907208c4 CL |
177 | u32 m; |
178 | u32 lines = -1; | |
179 | ||
70fd0710 CL |
180 | wr_dc_cst(IDC_UNALL); |
181 | wr_dc_cst(IDC_INVALL); | |
182 | wr_dc_cst(IDC_DISABLE); | |
907208c4 | 183 | |
70fd0710 CL |
184 | while (!((m = rd_dc_cst()) & IDC_CERR2)) { |
185 | wr_dc_adr(k); | |
186 | wr_dc_cst(IDC_LDLCK); | |
907208c4 CL |
187 | lines++; |
188 | k += 0x10; /* the number of bytes in a cacheline */ | |
189 | } | |
190 | ||
70fd0710 CL |
191 | wr_dc_cst(IDC_UNALL); |
192 | wr_dc_cst(IDC_INVALL); | |
907208c4 CL |
193 | |
194 | if (cacheon) | |
70fd0710 | 195 | wr_dc_cst(IDC_ENABLE); |
907208c4 | 196 | else |
70fd0710 | 197 | wr_dc_cst(IDC_DISABLE); |
907208c4 CL |
198 | |
199 | return lines << 4; | |
200 | }; | |
201 | ||
202 | /* ------------------------------------------------------------------------- */ | |
203 | ||
70fd0710 | 204 | void upmconfig(uint upm, uint *table, uint size) |
907208c4 CL |
205 | { |
206 | uint i; | |
207 | uint addr = 0; | |
ba3da734 CL |
208 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
209 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
907208c4 CL |
210 | |
211 | for (i = 0; i < size; i++) { | |
ba3da734 CL |
212 | out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */ |
213 | out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */ | |
907208c4 CL |
214 | addr++; |
215 | } | |
216 | } | |
217 | ||
218 | /* ------------------------------------------------------------------------- */ | |
219 | ||
70fd0710 | 220 | int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
907208c4 CL |
221 | { |
222 | ulong msr, addr; | |
223 | ||
ba3da734 | 224 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
907208c4 | 225 | |
ba3da734 CL |
226 | /* Checkstop Reset enable */ |
227 | setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR); | |
907208c4 CL |
228 | |
229 | /* Interrupts and MMU off */ | |
230 | __asm__ volatile ("mtspr 81, 0"); | |
70fd0710 | 231 | __asm__ volatile ("mfmsr %0" : "=r" (msr)); |
907208c4 CL |
232 | |
233 | msr &= ~0x1030; | |
70fd0710 | 234 | __asm__ volatile ("mtmsr %0" : : "r" (msr)); |
907208c4 CL |
235 | |
236 | /* | |
237 | * Trying to execute the next instruction at a non-existing address | |
238 | * should cause a machine check, resulting in reset | |
239 | */ | |
240 | #ifdef CONFIG_SYS_RESET_ADDRESS | |
241 | addr = CONFIG_SYS_RESET_ADDRESS; | |
242 | #else | |
243 | /* | |
70fd0710 CL |
244 | * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, |
245 | * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid address. | |
246 | * Better pick an address known to be invalid on your system and assign | |
247 | * it to CONFIG_SYS_RESET_ADDRESS. | |
907208c4 CL |
248 | * "(ulong)-1" used to be a good choice for many systems... |
249 | */ | |
70fd0710 | 250 | addr = CONFIG_SYS_MONITOR_BASE - sizeof(ulong); |
907208c4 | 251 | #endif |
70fd0710 | 252 | ((void (*)(void)) addr)(); |
907208c4 CL |
253 | return 1; |
254 | } | |
255 | ||
256 | /* ------------------------------------------------------------------------- */ | |
257 | ||
258 | /* | |
259 | * Get timebase clock frequency (like cpu_clk in Hz) | |
260 | * | |
261 | * See sections 14.2 and 14.6 of the User's Manual | |
262 | */ | |
70fd0710 | 263 | unsigned long get_tbclk(void) |
907208c4 | 264 | { |
70fd0710 | 265 | uint immr = get_immr(0); /* Return full IMMR contents */ |
ba3da734 | 266 | immap_t __iomem *immap = (immap_t __iomem *)(immr & 0xFFFF0000); |
907208c4 CL |
267 | ulong oscclk, factor, pll; |
268 | ||
ba3da734 | 269 | if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS) |
70fd0710 | 270 | return gd->cpu_clk / 16; |
907208c4 | 271 | |
ba3da734 | 272 | pll = in_be32(&immap->im_clkrst.car_plprcr); |
907208c4 CL |
273 | |
274 | #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) | |
275 | ||
276 | /* | |
277 | * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication | |
278 | * factor is calculated as follows: | |
279 | * | |
280 | * MFN | |
281 | * MFI + ------- | |
282 | * MFD + 1 | |
283 | * factor = ----------------- | |
284 | * (PDF + 1) * 2^S | |
285 | * | |
286 | */ | |
70fd0710 CL |
287 | factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD) + 1)) / |
288 | (PLPRCR_val(PDF) + 1) / (1 << PLPRCR_val(S)); | |
907208c4 CL |
289 | |
290 | oscclk = gd->cpu_clk / factor; | |
291 | ||
ba3da734 CL |
292 | if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 || |
293 | factor > 2) | |
70fd0710 | 294 | return oscclk / 4; |
ba3da734 | 295 | |
70fd0710 | 296 | return oscclk / 16; |
907208c4 CL |
297 | } |
298 | ||
299 | /* ------------------------------------------------------------------------- */ | |
300 | ||
301 | #if defined(CONFIG_WATCHDOG) | |
70fd0710 | 302 | void watchdog_reset(void) |
907208c4 | 303 | { |
70fd0710 | 304 | int re_enable = disable_interrupts(); |
907208c4 | 305 | |
ba3da734 | 306 | reset_8xx_watchdog((immap_t __iomem *)CONFIG_SYS_IMMR); |
907208c4 | 307 | if (re_enable) |
70fd0710 | 308 | enable_interrupts(); |
907208c4 CL |
309 | } |
310 | #endif /* CONFIG_WATCHDOG */ | |
311 | ||
312 | #if defined(CONFIG_WATCHDOG) | |
313 | ||
ba3da734 | 314 | void reset_8xx_watchdog(immap_t __iomem *immr) |
907208c4 CL |
315 | { |
316 | /* | |
317 | * All other boards use the MPC8xx Internal Watchdog | |
318 | */ | |
ba3da734 CL |
319 | out_be16(&immr->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ |
320 | out_be16(&immr->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ | |
907208c4 CL |
321 | } |
322 | #endif /* CONFIG_WATCHDOG */ | |
323 | ||
324 | /* | |
325 | * Initializes on-chip ethernet controllers. | |
326 | * to override, implement board_eth_init() | |
327 | */ | |
328 | int cpu_eth_init(bd_t *bis) | |
329 | { | |
330 | #if defined(FEC_ENET) | |
331 | fec_initialize(bis); | |
332 | #endif | |
333 | return 0; | |
334 | } |