xref: /netbsd/sys/arch/macppc/macppc/cpu.c (revision bf9ec67e)
1 /*	$NetBSD: cpu.c,v 1.25 2001/12/05 05:02:11 chs Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 Tsubai Masanari.
5  * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by
19  *	Internet Research Institute, Inc.
20  * 4. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "opt_l2cr_config.h"
36 #include "opt_multiprocessor.h"
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 
42 #include <uvm/uvm_extern.h>
43 #include <dev/ofw/openfirm.h>
44 #include <powerpc/mpc6xx/hid.h>
45 #include <powerpc/openpic.h>
46 
47 #include <machine/autoconf.h>
48 #include <machine/bat.h>
49 #include <machine/fpu.h>
50 #include <machine/pcb.h>
51 #include <machine/pio.h>
52 
53 int cpumatch(struct device *, struct cfdata *, void *);
54 void cpuattach(struct device *, struct device *, void *);
55 
56 void identifycpu(char *);
57 static void ohare_init(void);
58 int cpu_spinup(void);
59 void cpu_hatch(void);
60 void cpu_spinup_trampoline(void);
61 int cpuintr(void *v);
62 
63 struct cfattach cpu_ca = {
64 	sizeof(struct device), cpumatch, cpuattach
65 };
66 
67 extern struct cfdriver cpu_cd;
68 
69 #define HH_ARBCONF		0xf8000090
70 #define HH_INTR_SECONDARY	0xf80000c0
71 #define HH_INTR_PRIMARY		0xf3019000
72 #define GC_IPI_IRQ		30
73 
74 int
75 cpumatch(parent, cf, aux)
76 	struct device *parent;
77 	struct cfdata *cf;
78 	void *aux;
79 {
80 	struct confargs *ca = aux;
81 	int *reg = ca->ca_reg;
82 	int node;
83 
84 	if (strcmp(ca->ca_name, cpu_cd.cd_name) != 0)
85 		return 0;
86 
87 	node = OF_finddevice("/cpus");
88 	if (node != -1) {
89 		for (node = OF_child(node); node != 0; node = OF_peer(node)) {
90 			uint32_t cpunum;
91 			int l;
92 			l = OF_getprop(node, "reg", &cpunum, sizeof(cpunum));
93 			if (l == 4 && reg[0] == cpunum)
94 				return 1;
95 		}
96 	}
97 	switch (reg[0]) {
98 	case 0:	/* primary CPU */
99 		return 1;
100 	case 1:	/* secondary CPU */
101 		if (OF_finddevice("/hammerhead") != -1)
102 			if (in32rb(HH_ARBCONF) & 0x02)
103 				return 1;
104 		break;
105 	}
106 
107 	return 0;
108 }
109 
110 void
111 cpuattach(parent, self, aux)
112 	struct device *parent, *self;
113 	void *aux;
114 {
115 	struct cpu_info *ci;
116 	struct confargs *ca = aux;
117 	int id = ca->ca_reg[0];
118 
119 	ci = cpu_attach_common(self, id);
120 
121 	if (id > 0) {
122 #ifdef MULTIPROCESSOR
123 		if (ci != NULL)
124 			cpu_spinup();
125 #endif
126 		return;
127 	}
128 	if (ci == NULL)
129 		return;
130 
131 	if (OF_finddevice("/bandit/ohare") != -1) {
132 		printf("%s", self->dv_xname);
133 		ohare_init();
134 	}
135 }
136 
137 #define CACHE_REG 0xf8000000
138 
139 void
140 ohare_init()
141 {
142 	u_int *cache_reg, x;
143 
144 	/* enable L2 cache */
145 	cache_reg = mapiodev(CACHE_REG, NBPG);
146 	if (((cache_reg[2] >> 24) & 0x0f) >= 3) {
147 		x = cache_reg[4];
148 		if ((x & 0x10) == 0)
149                 	x |= 0x04000000;
150 		else
151                 	x |= 0x04000020;
152 
153 		cache_reg[4] = x;
154 		printf(": ohare L2 cache enabled\n");
155 	}
156 }
157 
158 #ifdef MULTIPROCESSOR
159 
160 struct cpu_hatch_data {
161 	int running;
162 	int pir;
163 	int hid0;
164 	int sdr1;
165 	int sr[16];
166 	int tbu, tbl;
167 };
168 
169 volatile struct cpu_hatch_data *cpu_hatch_data;
170 volatile int cpu_hatch_stack;
171 
172 int
173 cpu_spinup()
174 {
175 	volatile struct cpu_hatch_data hatch_data, *h = &hatch_data;
176 	int i;
177 	struct pcb *pcb;
178 	struct pglist mlist;
179 	int error;
180 	int size = 0;
181 	char *cp;
182 
183 	/*
184 	 * Allocate some contiguous pages for the idle PCB and stack
185 	 * from the lowest 256MB (because bat0 always maps it va == pa).
186 	 */
187 	TAILQ_INIT(&mlist);
188 	size += USPACE;
189 	size += 8192;	/* INTSTK */
190 	size += 4096;	/* SPILLSTK */
191 
192 	error = uvm_pglistalloc(size, 0x0, 0x10000000, 0, 0, &mlist, 1, 1);
193 	if (error) {
194 		printf(": unable to allocate idle stack\n");
195 		return -1;
196 	}
197 
198 	cp = (void *)VM_PAGE_TO_PHYS(TAILQ_FIRST(&mlist));
199 	memset(cp, 0, size);
200 
201 	pcb = (struct pcb *)cp;
202 	cp += USPACE;
203 	cpu_info[1].ci_idle_pcb = pcb;
204 
205 	cpu_info[1].ci_intstk = cp + 8192;
206 	cp += 8192;
207 	cpu_info[1].ci_spillstk = cp + 4096;
208 	cp += 4096;
209 
210 	/*
211 	 * Initialize the idle stack pointer, reserving space for an
212 	 * (empty) trapframe (XXX is the trapframe really necessary?)
213 	 */
214 	pcb->pcb_sp = (paddr_t)pcb + USPACE - sizeof(struct trapframe);
215 
216 	cpu_hatch_data = h;
217 	h->running = 0;
218 	h->pir = 1;
219 	cpu_hatch_stack = pcb->pcb_sp;
220 	cpu_info[1].ci_lasttb = cpu_info[0].ci_lasttb;
221 
222 	/* copy special registers */
223 	asm volatile ("mfspr %0,1008" : "=r"(h->hid0));
224 	asm volatile ("mfsdr1 %0" : "=r"(h->sdr1));
225 	for (i = 0; i < 16; i++)
226 		asm ("mfsrin %0,%1" : "=r"(h->sr[i]) : "r"(i << ADDR_SR_SHFT));
227 
228 	asm volatile ("sync; isync");
229 
230 	if (openpic_base) {
231 		/* XXX */
232 		panic("cpu_spinup");
233 	} else {
234 		/* Start secondary cpu and stop timebase. */
235 		out32(0xf2800000, (int)cpu_spinup_trampoline);
236 		out32(HH_INTR_SECONDARY, ~0);
237 		out32(HH_INTR_SECONDARY, 0);
238 
239 		/* sync timebase (XXX shouldn't be zero'ed) */
240 		asm volatile ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0));
241 
242 		/*
243 		 * wait for secondary spin up (1.5ms @ 604/200MHz)
244 		 * XXX we cannot use delay() here because timebase is not
245 		 * running.
246 		 */
247 		for (i = 0; i < 100000; i++)
248 			if (h->running)
249 				break;
250 
251 		/* Start timebase. */
252 		out32(0xf2800000, 0x100);
253 		out32(HH_INTR_SECONDARY, ~0);
254 		out32(HH_INTR_SECONDARY, 0);
255 	}
256 
257 	delay(100000);		/* wait for secondary printf */
258 
259 	if (h->running == 0) {
260 		printf(": secondary cpu didn't start\n");
261 		return -1;
262 	}
263 
264 	if (!openpic_base) {
265 		/* Register IPI. */
266 		intr_establish(GC_IPI_IRQ, IST_LEVEL, IPL_HIGH, cpuintr, NULL);
267 	}
268 
269 	return 0;
270 }
271 
272 volatile static int start_secondary_cpu;
273 extern long ticks_per_intr;
274 
275 void
276 cpu_hatch()
277 {
278 	volatile struct cpu_hatch_data *h = cpu_hatch_data;
279 	u_int msr;
280 	int i;
281 	char model[80];
282 
283 	/* Initialize timebase. */
284 	asm ("mttbl %0; mttbu %0; mttbl %0" :: "r"(0));
285 
286 	/* Set PIR (Processor Identification Register).  i.e. whoami */
287 	asm volatile ("mtspr 1023,%0" :: "r"(h->pir));
288 	asm volatile ("mtsprg 0,%0" :: "r"(&cpu_info[h->pir]));
289 
290 	/* Initialize MMU. */
291 	asm ("mtibatu 0,%0" :: "r"(0));
292 	asm ("mtibatu 1,%0" :: "r"(0));
293 	asm ("mtibatu 2,%0" :: "r"(0));
294 	asm ("mtibatu 3,%0" :: "r"(0));
295 	asm ("mtdbatu 0,%0" :: "r"(0));
296 	asm ("mtdbatu 1,%0" :: "r"(0));
297 	asm ("mtdbatu 2,%0" :: "r"(0));
298 	asm ("mtdbatu 3,%0" :: "r"(0));
299 
300 	asm ("mtspr 1008,%0" :: "r"(h->hid0));
301 
302 	asm ("mtibatl 0,%0; mtibatu 0,%1;"
303 	     "mtdbatl 0,%0; mtdbatu 0,%1;"
304 		:: "r"(battable[0].batl), "r"(battable[0].batu));
305 
306 	/* XXX obio (for now) */
307 	asm ("mtibatl 1,%0; mtibatu 1,%1;"
308 	     "mtdbatl 1,%0; mtdbatu 1,%1;"
309 		:: "r"(battable[0xf].batl), "r"(battable[0xf].batu));
310 
311 	for (i = 0; i < 16; i++)
312 		asm ("mtsrin %0,%1" :: "r"(h->sr[i]), "r"(i << ADDR_SR_SHFT));
313 	asm ("mtsdr1 %0" :: "r"(h->sdr1));
314 
315 	asm volatile ("isync");
316 
317 	/* Enable I/D address translations. */
318 	asm volatile ("mfmsr %0" : "=r"(msr));
319 	msr |= PSL_IR|PSL_DR|PSL_ME|PSL_RI;
320 	asm volatile ("mtmsr %0" :: "r"(msr));
321 
322 	asm volatile ("sync; isync");
323 	h->running = 1;
324 
325 	cpu_identify(model, sizeof(model));
326 	printf(": %s, ID %d\n", model, cpu_number());
327 
328 	while (start_secondary_cpu == 0);
329 
330 	printf("secondary CPU started\n");
331 	asm volatile ("mtdec %0" :: "r"(ticks_per_intr));
332 
333 	if (!openpic_base)
334 		out32(HH_INTR_SECONDARY, ~0);	/* Reset interrupt. */
335 
336 	curcpu()->ci_ipending = 0;
337 	curcpu()->ci_cpl = 0;
338 }
339 
340 void
341 cpu_boot_secondary_processors()
342 {
343 	start_secondary_cpu = 1;
344 }
345 
346 /*static*/ volatile int IPI[2];
347 
348 void
349 macppc_send_ipi(ci, mesg)
350 	volatile struct cpu_info *ci;
351 	int mesg;
352 {
353 	int cpu_id = ci->ci_cpuid;
354 
355 	/* printf("send_ipi(%d,%d)\n", cpu_id, mesg); */
356 	IPI[cpu_id] |= mesg;
357 
358 	if (openpic_base) {
359 		/* XXX */
360 	} else {
361 		switch (cpu_id) {
362 		case 0:
363 			in32(HH_INTR_PRIMARY);
364 			break;
365 		case 1:
366 			out32(HH_INTR_SECONDARY, ~0);
367 			out32(HH_INTR_SECONDARY, 0);
368 			break;
369 		}
370 	}
371 }
372 
373 int
374 cpuintr(v)
375 	void *v;
376 {
377 	int cpu_id = cpu_number();
378 	int msr;
379 
380 	/* printf("cpuintr{%d}\n", cpu_id); */
381 
382 	if (IPI[cpu_id] & MACPPC_IPI_FLUSH_FPU) {
383 		if (curcpu()->ci_fpuproc) {
384 			save_fpu(curcpu()->ci_fpuproc);
385 			if (curcpu()->ci_fpuproc)
386 				panic("cpuintr");
387 		}
388 	}
389 	if (IPI[cpu_id] & MACPPC_IPI_HALT) {
390 		printf("halt{%d}\n", cpu_id);
391 		asm volatile ("mfmsr %0" : "=r"(msr));
392 		msr &= ~PSL_EE;
393 		msr |= PSL_POW;
394 		for (;;) {
395 			asm volatile ("sync; isync");
396 			asm volatile ("mtmsr %0" :: "r"(msr));
397 		}
398 	}
399 	IPI[cpu_id] = 0;
400 
401 	return 1;
402 }
403 #endif /* MULTIPROCESSOR */
404