xref: /netbsd/sys/arch/powerpc/ibm4xx/cpu.c (revision bf9ec67e)
1 /*	$NetBSD: cpu.c,v 1.2 2002/03/15 21:12:07 eeh Exp $	*/
2 
3 /*
4  * Copyright 2001 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/properties.h>
42 
43 #include <machine/autoconf.h>
44 #include <machine/dcr.h>
45 #include <machine/cpu.h>
46 
47 struct cputab {
48 	int version;
49 	char *name;
50 };
51 static struct cputab models[] = {
52 	{ PVR_401A1 >> 16, "401A1" },
53 	{ PVR_401B2 >> 16, "401B21" },
54 	{ PVR_401C2 >> 16, "401C2" },
55 	{ PVR_401D2 >> 16, "401D2" },
56 	{ PVR_401E2 >> 16, "401E2" },
57 	{ PVR_401F2 >> 16, "401F2" },
58 	{ PVR_401G2 >> 16, "401G2" },
59 	{ PVR_403 >> 16, "403" },
60 	{ PVR_405GP >> 16, "405GP" },
61 	{ 0,		    NULL }
62 };
63 
64 static int	cpumatch(struct device *, struct cfdata *, void *);
65 static void	cpuattach(struct device *, struct device *, void *);
66 
67 /*
68  * Arguably the ECC stuff belongs somewhere else....
69  */
70 int intr_ecc(void *);
71 
72 u_quad_t		intr_ecc_tb;
73 u_quad_t		intr_ecc_iv;	 /* Interval */
74 u_int32_t		intr_ecc_cnt;
75 
76 struct cfattach cpu_ca = {
77 	sizeof(struct device), cpumatch, cpuattach
78 };
79 
80 int ncpus;
81 
82 struct cpu_info cpu_info_store;
83 
84 int cpufound = 0;
85 
86 static int
87 cpumatch(struct device *parent, struct cfdata *cf, void *aux)
88 {
89 	struct mainbus_attach_args *maa = aux;
90 
91 	/* make sure that we're looking for a CPU */
92 	if (strcmp(maa->mb_name, cf->cf_driver->cd_name) != 0)
93                 return (0);
94 
95 	return !cpufound;
96 }
97 
98 static void
99 cpuattach(struct device *parent, struct device *self, void *aux)
100 {
101 	int pvr, cpu;
102 	int own, pcf, cas, pcl, aid;
103 	struct cputab *cp = models;
104 	unsigned int processor_freq;
105 
106 	if (board_info_get("processor-frequency",
107 		&processor_freq, sizeof(processor_freq)) == -1)
108 		panic("no processor-frequency");
109 
110 	cpufound++;
111 	ncpus++;
112 
113 	asm ("mfpvr %0" : "=r"(pvr));
114 	cpu = pvr >> 16;
115 
116 	/* Break PVR up into separate fields and print them out. */
117 	own = (pvr >> 20) & 0xfff;
118 	pcf = (pvr >> 16) & 0xf;
119 	cas = (pvr >> 10) & 0x3f;
120 	pcl = (pvr >> 6) & 0xf;
121 	aid = pvr & 0x3f;
122 
123 	while (cp->name) {
124 		if (cp->version == cpu)
125 			break;
126 		cp++;
127 	}
128 	if (cp->name)
129 		strcpy(cpu_model, cp->name);
130 	else
131 		sprintf(cpu_model, "Version 0x%x", cpu);
132 	sprintf(cpu_model + strlen(cpu_model), " (Revision %d.%d)",
133 		(pvr >> 8) & 0xff, pvr & 0xff);
134 
135 #if 1
136 	printf(": %dMHz %s\n", processor_freq / 1000 / 1000,
137 	    cpu_model);
138 #endif
139 
140 	cpu_probe_cache();
141 
142 	printf("Instruction cache size %d line size %d\n",
143 		curcpu()->ci_ci.icache_size, curcpu()->ci_ci.icache_line_size);
144 	printf("Data cache size %d line size %d\n",
145 		curcpu()->ci_ci.dcache_size, curcpu()->ci_ci.dcache_line_size);
146 
147 #ifdef DEBUG
148 	/* It sux that the cache info here is useless. */
149 	printf("PVR: owner %x core family %x cache %x version %x asic %x\n",
150 		own, pcf, cas, pcl, aid);
151 #endif
152 
153 	/* Initialize ECC error-logging handler.  This is always enabled,
154 	 * but it will never be called on systems that do not have ECC
155 	 * enabled by POST code in the bootloader.
156          */
157 
158 	printf("Enabling ecc handler\n");
159 	intr_ecc_tb = 0;
160 	intr_ecc_iv = processor_freq; /* Set interval */
161 	intr_ecc_cnt = 0;
162 
163 	intr_establish(16, IST_LEVEL, IPL_SERIAL, intr_ecc, NULL);
164 }
165 
166 /*
167  * This routine must be explicitly called to initialize the
168  * CPU cache information so cache flushe and memcpy operation
169  * work.
170  */
171 void
172 cpu_probe_cache()
173 {
174 	int version;
175 
176 	/*
177 	 * First we need to identify the cpu and determine the
178 	 * cache line size, or things like memset/memcpy may lose
179 	 * badly.
180 	 */
181 	__asm __volatile("mfpvr %0" : "=r" (version));
182 	switch (version & 0xffff0000) {
183 	case PVR_401A1:
184 		curcpu()->ci_ci.dcache_size = 1024;
185 		curcpu()->ci_ci.dcache_line_size = 16;
186 		curcpu()->ci_ci.icache_size = 2848;
187 		curcpu()->ci_ci.icache_line_size = 16;
188 		break;
189 	case PVR_401B2:
190 		curcpu()->ci_ci.dcache_size = 8192;
191 		curcpu()->ci_ci.dcache_line_size = 16;
192 		curcpu()->ci_ci.icache_size = 16384;
193 		curcpu()->ci_ci.icache_line_size = 16;
194 		break;
195 	case PVR_401C2:
196 		curcpu()->ci_ci.dcache_size = 8192;
197 		curcpu()->ci_ci.dcache_line_size = 16;
198 		curcpu()->ci_ci.icache_size = 0;
199 		curcpu()->ci_ci.icache_line_size = 16;
200 		break;
201 	case PVR_401D2:
202 		curcpu()->ci_ci.dcache_size = 2848;
203 		curcpu()->ci_ci.dcache_line_size = 16;
204 		curcpu()->ci_ci.icache_size = 4096;
205 		curcpu()->ci_ci.icache_line_size = 16;
206 		break;
207 	case PVR_401E2:
208 		curcpu()->ci_ci.dcache_size = 0;
209 		curcpu()->ci_ci.dcache_line_size = 16;
210 		curcpu()->ci_ci.icache_size = 0;
211 		curcpu()->ci_ci.icache_line_size = 16;
212 		break;
213 	case PVR_401F2:
214 		curcpu()->ci_ci.dcache_size = 2048;
215 		curcpu()->ci_ci.dcache_line_size = 16;
216 		curcpu()->ci_ci.icache_size = 2848;
217 		curcpu()->ci_ci.icache_line_size = 16;
218 		break;
219 	case PVR_401G2:
220 		curcpu()->ci_ci.dcache_size = 2848;
221 		curcpu()->ci_ci.dcache_line_size = 16;
222 		curcpu()->ci_ci.icache_size = 8192;
223 		curcpu()->ci_ci.icache_line_size = 16;
224 		break;
225 	case PVR_403:
226 		curcpu()->ci_ci.dcache_line_size = 16;
227 		curcpu()->ci_ci.icache_line_size = 16;
228 		break;
229 	case PVR_405GP:
230 		curcpu()->ci_ci.dcache_size = 8192;
231 		curcpu()->ci_ci.dcache_line_size = 32;
232 		curcpu()->ci_ci.icache_size = 8192;
233 		curcpu()->ci_ci.icache_line_size = 32;
234 		break;
235 	default:
236 		/*
237 		 * Unknown CPU type.  For safety we'll specify a
238 		 * cache with a 4-byte line size.  That way cache
239 		 * flush routines won't miss any lines.
240 		 */
241 		curcpu()->ci_ci.dcache_line_size = 4;
242 		curcpu()->ci_ci.icache_line_size = 4;
243 		break;
244 	}
245 
246 }
247 
248 /*
249  * These small routines may have to be replaced,
250  * if/when we support processors other that the 604.
251  */
252 
253 void
254 dcache_flush_page(vaddr_t va)
255 {
256 	int i;
257 
258 	if (curcpu()->ci_ci.dcache_line_size)
259 		for (i = 0; i < NBPG; i += curcpu()->ci_ci.dcache_line_size)
260 			asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
261 	asm volatile("sync;isync" : : );
262 }
263 
264 void
265 icache_flush_page(vaddr_t va)
266 {
267 	int i;
268 
269 	if (curcpu()->ci_ci.icache_line_size)
270 		for (i = 0; i < NBPG; i += curcpu()->ci_ci.icache_line_size)
271 			asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
272 	asm volatile("sync;isync" : : );
273 }
274 
275 void
276 dcache_flush(vaddr_t va, vsize_t len)
277 {
278 	int i;
279 
280 	if (len == 0)
281 		return;
282 
283 	/* Make sure we flush all cache lines */
284 	len += va & (curcpu()->ci_ci.dcache_line_size-1);
285 	if (curcpu()->ci_ci.dcache_line_size)
286 		for (i = 0; i < len; i += curcpu()->ci_ci.dcache_line_size)
287 			asm volatile("dcbf %0,%1" : : "r" (va), "r" (i));
288 	asm volatile("sync;isync" : : );
289 }
290 
291 void
292 icache_flush(vaddr_t va, vsize_t len)
293 {
294 	int i;
295 
296 	if (len == 0)
297 		return;
298 
299 	/* Make sure we flush all cache lines */
300 	len += va & (curcpu()->ci_ci.icache_line_size-1);
301 	if (curcpu()->ci_ci.icache_line_size)
302 		for (i = 0; i < len; i += curcpu()->ci_ci.icache_line_size)
303 			asm volatile("icbi %0,%1" : : "r" (va), "r" (i));
304 	asm volatile("sync;isync" : : );
305 }
306 
307 /*
308  * ECC fault handler.
309  */
310 int
311 intr_ecc(void * arg)
312 {
313 	u_int32_t		esr, ear;
314 	int			ce, ue;
315 	u_quad_t		tb;
316 	u_long			tmp, msr, dat;
317 	unsigned int		memsiz;
318 
319 	if (board_info_get("mem-size", &memsiz, sizeof(memsiz)) == -1)
320 		panic("no mem-size");
321 
322 	/* This code needs to be improved to handle double-bit errors */
323 	/* in some intelligent fashion. */
324 
325 	mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_ECCESR);
326 	esr = mfdcr(DCR_SDRAM0_CFGDATA);
327 
328 	mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_BEAR);
329 	ear = mfdcr(DCR_SDRAM0_CFGDATA);
330 
331 	/* Always clear the error to stop the intr ASAP. */
332 
333 	mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_ECCESR);
334 	mtdcr(DCR_SDRAM0_CFGDATA, 0xffffffff);
335 
336 	if (esr == 0x00) {
337 		/* No current error.  Could happen due to intr. nesting */
338 		return(1);
339 	};
340 
341 	/* Only report errors every once per second max. Do this using the TB, */
342 	/* because the system time (via microtime) may be adjusted when the date is set */
343         /* and can't reliably be used to measure intervals. */
344 
345 	asm ("1: mftbu %0; mftb %0+1; mftbu %1; cmpw %0,%1; bne 1b"
346 		: "=r"(tb), "=r"(tmp));
347 	intr_ecc_cnt++;
348 
349 	if ((tb - intr_ecc_tb) < intr_ecc_iv) {
350 		return(1);
351 	};
352 
353 	ce = (esr & SDRAM0_ECCESR_CE) != 0x00;
354 	ue = (esr & SDRAM0_ECCESR_UE) != 0x00;
355 
356 	printf("ECC: Error CNT=%d ESR=%x EAR=%x %s BKNE=%d%d%d%d "
357 		"BLCE=%d%d%d%d CBE=%d%d.\n",
358 		intr_ecc_cnt, esr, ear,
359 		(ue) ? "Uncorrectable" : "Correctable",
360 		((esr & SDRAM0_ECCESR_BKEN(0)) != 0x00),
361 		((esr & SDRAM0_ECCESR_BKEN(1)) != 0x00),
362 		((esr & SDRAM0_ECCESR_BKEN(2)) != 0x00),
363 		((esr & SDRAM0_ECCESR_BKEN(3)) != 0x00),
364 		((esr & SDRAM0_ECCESR_BLCEN(0)) != 0x00),
365 		((esr & SDRAM0_ECCESR_BLCEN(1)) != 0x00),
366 		((esr & SDRAM0_ECCESR_BLCEN(2)) != 0x00),
367 		((esr & SDRAM0_ECCESR_BLCEN(3)) != 0x00),
368 		((esr & SDRAM0_ECCESR_CBEN(0)) != 0x00),
369 		((esr & SDRAM0_ECCESR_CBEN(1)) != 0x00));
370 
371 	/* Should check for uncorrectable errors and panic... */
372 
373 	if (intr_ecc_cnt > 1000) {
374 		printf("ECC: Too many errors, recycling entire "
375 			"SDRAM (size = %d).\n", memsiz);
376 
377 		/* Can this code be changed to run without disabling data MMU and disabling intrs? */
378 		/* Does kernel always map all of physical RAM VA=PA? If so, just loop over lowmem. */
379 
380 		asm volatile(
381 			"mfmsr 	%0;"
382 			"li	%1, 0x00;"
383 			"ori	%1, %1, 0x8010;"
384 			"andc	%1, %0, %1;"
385 			"mtmsr	%1;"
386 			"sync;isync;"
387 			"li	%1, 0x00;"
388 			"1:"
389 			"dcbt	0, %1;"
390 			"sync;isync;"
391 			"lwz	%2, 0(%1);"
392 			"stw	%2, 0(%1);"
393 			"sync;isync;"
394 			"dcbf	0, %1;"
395 			"sync;isync;"
396 			"addi	%1, %1, 0x20;"
397 			"addic.	%3, %3, -0x20;"
398 			"bge 	1b;"
399 			"mtmsr %0;"
400 			"sync;isync;"
401 		: "=&r" (msr), "=&r" (tmp), "=&r" (dat)
402 		: "r" (memsiz) : "0" );
403 
404 		mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_ECCESR);
405 		esr = mfdcr(DCR_SDRAM0_CFGDATA);
406 
407 		mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_ECCESR);
408 		mtdcr(DCR_SDRAM0_CFGDATA, 0xffffffff);
409 
410 		/* Correctable errors here are OK, mem should be clean now. */
411 		/* Should check for uncorrectable errors and panic... */
412 		printf("ECC: Recycling complete, ESR=%x. "
413 			"Checking for persistent errors.\n", esr);
414 
415 		asm volatile(
416 			"mfmsr 	%0;"
417 			"li	%1, 0x00;"
418 			"ori	%1, %1, 0x8010;"
419 			"andc	%1, %0, %1;"
420 			"mtmsr	%1;"
421 			"sync;isync;"
422 			"li	%1, 0x00;"
423 			"1:"
424 			"dcbt	0, %1;"
425 			"sync;isync;"
426 			"lwz	%2, 0(%1);"
427 			"stw	%2, 0(%1);"
428 			"sync;isync;"
429 			"dcbf	0, %1;"
430 			"sync;isync;"
431 			"addi	%1, %1, 0x20;"
432 			"addic.	%3, %3, -0x20;"
433 			"bge 	1b;"
434 			"mtmsr %0;"
435 			"sync;isync;"
436 		: "=&r" (msr), "=&r" (tmp), "=&r" (dat)
437 		: "r" (memsiz) : "0" );
438 
439 		mtdcr(DCR_SDRAM0_CFGADDR, DCR_SDRAM0_ECCESR);
440 		esr = mfdcr(DCR_SDRAM0_CFGDATA);
441 
442 		/* If esr is non zero here, we're screwed.  Should check this and panic. */
443 		printf("ECC: Persistent error check complete, "
444 			"final ESR=%x.\n", esr);
445 	};
446 
447 	intr_ecc_tb = tb;
448 	intr_ecc_cnt = 0;
449 
450 	return(1);
451 };
452