]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/powerpc/cpu/mpc8xx/cpu.c
powerpc: Partialy restore core of mpc8xx
[people/ms/u-boot.git] / arch / powerpc / cpu / mpc8xx / cpu.c
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
40 static int check_CPU (long clock, uint pvr, uint immr)
41 {
42 char *id_str =
43 NULL;
44 volatile immap_t *immap = (immap_t *) (immr & 0xFFFF0000);
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) |
57 immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)];
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;
76 case 0x09000000: pre = 'M'; mid = suf = ""; m = 1;
77 if (id_str == NULL)
78 id_str = "PC885"; /* 870/875/880/885 */
79 break;
80
81 default: suf = NULL; break;
82 }
83
84 if (id_str == NULL)
85 id_str = "PC86x"; /* Unknown 86x chip */
86 if (suf)
87 printf ("%c%s%sZPnn%s", pre, id_str, mid, suf);
88 else
89 printf ("unknown M%s (0x%08x)", id_str, k);
90
91 printf (" at %s MHz: ", strmhz (buf, clock));
92
93 print_size(checkicache(), " I-Cache ");
94 print_size(checkdcache(), " D-Cache");
95
96 /* do we have a FEC (860T/P or 852/859/866/885)? */
97
98 immap->im_cpm.cp_fec.fec_addr_low = 0x12345678;
99 if (immap->im_cpm.cp_fec.fec_addr_low == 0x12345678) {
100 printf (" FEC present");
101 }
102
103 if (!m) {
104 puts (cpu_warning);
105 }
106
107 putc ('\n');
108
109 return 0;
110 }
111
112 /* ------------------------------------------------------------------------- */
113
114 int checkcpu (void)
115 {
116 ulong clock = gd->cpu_clk;
117 uint immr = get_immr (0); /* Return full IMMR contents */
118 uint pvr = get_pvr ();
119
120 puts ("CPU: ");
121
122 return check_CPU (clock, pvr, immr);
123 }
124
125 /* ------------------------------------------------------------------------- */
126 /* L1 i-cache */
127
128 int checkicache (void)
129 {
130 volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
131 volatile memctl8xx_t *memctl = &immap->im_memctl;
132 u32 cacheon = rd_ic_cst () & IDC_ENABLED;
133
134 u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
135 u32 m;
136 u32 lines = -1;
137
138 wr_ic_cst (IDC_UNALL);
139 wr_ic_cst (IDC_INVALL);
140 wr_ic_cst (IDC_DISABLE);
141 __asm__ volatile ("isync");
142
143 while (!((m = rd_ic_cst ()) & IDC_CERR2)) {
144 wr_ic_adr (k);
145 wr_ic_cst (IDC_LDLCK);
146 __asm__ volatile ("isync");
147
148 lines++;
149 k += 0x10; /* the number of bytes in a cacheline */
150 }
151
152 wr_ic_cst (IDC_UNALL);
153 wr_ic_cst (IDC_INVALL);
154
155 if (cacheon)
156 wr_ic_cst (IDC_ENABLE);
157 else
158 wr_ic_cst (IDC_DISABLE);
159
160 __asm__ volatile ("isync");
161
162 return lines << 4;
163 };
164
165 /* ------------------------------------------------------------------------- */
166 /* L1 d-cache */
167 /* call with cache disabled */
168
169 int checkdcache (void)
170 {
171 volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
172 volatile memctl8xx_t *memctl = &immap->im_memctl;
173 u32 cacheon = rd_dc_cst () & IDC_ENABLED;
174
175 u32 k = memctl->memc_br0 & ~0x00007fff; /* probe in flash memoryarea */
176 u32 m;
177 u32 lines = -1;
178
179 wr_dc_cst (IDC_UNALL);
180 wr_dc_cst (IDC_INVALL);
181 wr_dc_cst (IDC_DISABLE);
182
183 while (!((m = rd_dc_cst ()) & IDC_CERR2)) {
184 wr_dc_adr (k);
185 wr_dc_cst (IDC_LDLCK);
186 lines++;
187 k += 0x10; /* the number of bytes in a cacheline */
188 }
189
190 wr_dc_cst (IDC_UNALL);
191 wr_dc_cst (IDC_INVALL);
192
193 if (cacheon)
194 wr_dc_cst (IDC_ENABLE);
195 else
196 wr_dc_cst (IDC_DISABLE);
197
198 return lines << 4;
199 };
200
201 /* ------------------------------------------------------------------------- */
202
203 void upmconfig (uint upm, uint * table, uint size)
204 {
205 uint i;
206 uint addr = 0;
207 volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
208 volatile memctl8xx_t *memctl = &immap->im_memctl;
209
210 for (i = 0; i < size; i++) {
211 memctl->memc_mdr = table[i]; /* (16-15) */
212 memctl->memc_mcr = addr | upm; /* (16-16) */
213 addr++;
214 }
215 }
216
217 /* ------------------------------------------------------------------------- */
218
219 int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
220 {
221 ulong msr, addr;
222
223 volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
224
225 immap->im_clkrst.car_plprcr |= PLPRCR_CSR; /* Checkstop Reset enable */
226
227 /* Interrupts and MMU off */
228 __asm__ volatile ("mtspr 81, 0");
229 __asm__ volatile ("mfmsr %0":"=r" (msr));
230
231 msr &= ~0x1030;
232 __asm__ volatile ("mtmsr %0"::"r" (msr));
233
234 /*
235 * Trying to execute the next instruction at a non-existing address
236 * should cause a machine check, resulting in reset
237 */
238 #ifdef CONFIG_SYS_RESET_ADDRESS
239 addr = CONFIG_SYS_RESET_ADDRESS;
240 #else
241 /*
242 * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, CONFIG_SYS_MONITOR_BASE
243 * - sizeof (ulong) is usually a valid address. Better pick an address
244 * known to be invalid on your system and assign it to CONFIG_SYS_RESET_ADDRESS.
245 * "(ulong)-1" used to be a good choice for many systems...
246 */
247 addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
248 #endif
249 ((void (*)(void)) addr) ();
250 return 1;
251 }
252
253 /* ------------------------------------------------------------------------- */
254
255 /*
256 * Get timebase clock frequency (like cpu_clk in Hz)
257 *
258 * See sections 14.2 and 14.6 of the User's Manual
259 */
260 unsigned long get_tbclk (void)
261 {
262 uint immr = get_immr (0); /* Return full IMMR contents */
263 volatile immap_t *immap = (volatile immap_t *)(immr & 0xFFFF0000);
264 ulong oscclk, factor, pll;
265
266 if (immap->im_clkrst.car_sccr & SCCR_TBS) {
267 return (gd->cpu_clk / 16);
268 }
269
270 pll = immap->im_clkrst.car_plprcr;
271
272 #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT)
273
274 /*
275 * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication
276 * factor is calculated as follows:
277 *
278 * MFN
279 * MFI + -------
280 * MFD + 1
281 * factor = -----------------
282 * (PDF + 1) * 2^S
283 *
284 */
285 factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN)/(PLPRCR_val(MFD)+1))/
286 (PLPRCR_val(PDF)+1) / (1<<PLPRCR_val(S));
287
288 oscclk = gd->cpu_clk / factor;
289
290 if ((immap->im_clkrst.car_sccr & SCCR_RTSEL) == 0 || factor > 2) {
291 return (oscclk / 4);
292 }
293 return (oscclk / 16);
294 }
295
296 /* ------------------------------------------------------------------------- */
297
298 #if defined(CONFIG_WATCHDOG)
299 void watchdog_reset (void)
300 {
301 int re_enable = disable_interrupts ();
302
303 reset_8xx_watchdog ((immap_t *) CONFIG_SYS_IMMR);
304 if (re_enable)
305 enable_interrupts ();
306 }
307 #endif /* CONFIG_WATCHDOG */
308
309 #if defined(CONFIG_WATCHDOG)
310
311 void reset_8xx_watchdog (volatile immap_t * immr)
312 {
313 /*
314 * All other boards use the MPC8xx Internal Watchdog
315 */
316 immr->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
317 immr->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
318 }
319 #endif /* CONFIG_WATCHDOG */
320
321 /*
322 * Initializes on-chip ethernet controllers.
323 * to override, implement board_eth_init()
324 */
325 int cpu_eth_init(bd_t *bis)
326 {
327 #if defined(FEC_ENET)
328 fec_initialize(bis);
329 #endif
330 return 0;
331 }