xref: /netbsd-src/sys/arch/prep/prep/machdep.c (revision f36002f244a49908fef9cba8789032bdbf48d572)
1 /*	$NetBSD: machdep.c,v 1.79 2024/03/05 14:15:34 thorpej Exp $	*/
2 
3 /*
4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5  * Copyright (C) 1995, 1996 TooLs GmbH.
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 TooLs GmbH.
19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.79 2024/03/05 14:15:34 thorpej Exp $");
36 
37 #include "opt_compat_netbsd.h"
38 #include "opt_openpic.h"
39 
40 #include <sys/param.h>
41 #include <sys/buf.h>
42 #include <sys/bus.h>
43 #include <sys/conf.h>
44 #include <sys/device.h>
45 #include <sys/exec.h>
46 #include <sys/extent.h>
47 #include <sys/intr.h>
48 #include <sys/kernel.h>
49 #include <sys/mbuf.h>
50 #include <sys/mount.h>
51 #include <sys/msgbuf.h>
52 #include <sys/proc.h>
53 #include <sys/reboot.h>
54 #include <sys/syscallargs.h>
55 #include <sys/syslog.h>
56 #include <sys/systm.h>
57 #include <sys/sysctl.h>
58 
59 #include <uvm/uvm_extern.h>
60 
61 #include <machine/autoconf.h>
62 #include <machine/bootinfo.h>
63 #include <machine/platform.h>
64 #include <machine/powerpc.h>
65 #include <machine/residual.h>
66 
67 #include <powerpc/pmap.h>
68 #include <powerpc/trap.h>
69 
70 #include <powerpc/oea/bat.h>
71 #include <powerpc/openpic.h>
72 #include <powerpc/pic/picvar.h>
73 #ifdef MULTIPROCESSOR
74 #include <powerpc/pic/ipivar.h>
75 #endif
76 
77 #include <dev/cons.h>
78 
79 #include "com.h"
80 #if (NCOM > 0)
81 #include <sys/termios.h>
82 #include <dev/ic/comreg.h>
83 #include <dev/ic/comvar.h>
84 #endif
85 
86 #include "opt_interrupt.h"
87 
88 void initppc(u_long, u_long, u_int, void *);
89 void dumpsys(void);
90 static void prep_init(void);
91 static void init_intr(void);
92 
93 char bootinfo[BOOTINFO_MAXSIZE];
94 char bootpath[256];
95 
96 vaddr_t prep_intr_reg;			/* PReP interrupt vector register */
97 uint32_t prep_intr_reg_off;		/* IVR offset within the mapped page */
98 
99 #define	OFMEMREGIONS	32
100 struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
101 
102 paddr_t avail_end;			/* XXX temporary */
103 struct pic_ops *isa_pic;
104 int isa_pcmciamask = 0x8b28;
105 uint32_t busfreq;
106 
107 extern int primary_pic;
108 extern struct platform_quirkdata platform_quirks[];
109 
110 RESIDUAL *res;
111 RESIDUAL resdata;
112 
113 void
initppc(u_long startkernel,u_long endkernel,u_int args,void * btinfo)114 initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo)
115 {
116 
117 	/*
118 	 * copy bootinfo
119 	 */
120 	memcpy(bootinfo, btinfo, sizeof(bootinfo));
121 
122 	/*
123 	 * copy residual data
124 	 */
125 	{
126 		struct btinfo_residual *resinfo;
127 
128 		resinfo =
129 		    (struct btinfo_residual *)lookup_bootinfo(BTINFO_RESIDUAL);
130 		if (!resinfo)
131 			panic("not found residual information in bootinfo");
132 
133 		if (((RESIDUAL *)resinfo->addr != 0) &&
134 		    ((RESIDUAL *)resinfo->addr)->ResidualLength != 0) {
135 			memcpy(&resdata, resinfo->addr, sizeof(resdata));
136 			res = &resdata;
137 		} else
138 			panic("No residual data.");
139 	}
140 	aprint_normal("got residual data\n");
141 
142 	/*
143 	 * Set memory region
144 	 */
145 	{
146 		u_long memsize = res->TotalMemory;
147 
148 		physmemr[0].start = 0;
149 		physmemr[0].size = memsize & ~PGOFSET;
150 		availmemr[0].start = (endkernel + PGOFSET) & ~PGOFSET;
151 		availmemr[0].size = memsize - availmemr[0].start;
152 	}
153 	avail_end = physmemr[0].start + physmemr[0].size;    /* XXX temporary */
154 
155 	/*
156 	 * Set CPU clock
157 	 */
158 	{
159 		struct btinfo_clock *clockinfo;
160 		extern u_long ticks_per_sec, ns_per_tick;
161 		VPD *vpd;
162 
163 		clockinfo =
164 		    (struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK);
165 		if (!clockinfo)
166 			panic("not found clock information in bootinfo");
167 
168 		ticks_per_sec = clockinfo->ticks_per_sec;
169 		ns_per_tick = 1000000000 / ticks_per_sec;
170 
171 		vpd = &res->VitalProductData;
172 		busfreq = be32toh(vpd->ProcessorBusHz);
173 	}
174 
175 	prep_initppc(startkernel, endkernel, args,
176 	    /* rs6k-style PCI bridge */
177 	    0xbf800000, BAT_BL_8M,		/* XXX magic number */
178 	    0);
179 }
180 
181 /*
182  * Machine dependent startup code.
183  */
184 void
cpu_startup(void)185 cpu_startup(void)
186 {
187 	/*
188 	 * Do common startup.
189 	 */
190 	oea_startup(res->VitalProductData.PrintableModel);
191 
192 	/*
193 	 * General prep setup using pnp residual. Also provides for
194 	 * external interrupt handler install
195 	 */
196 	prep_init();
197 
198 	/*
199 	 * Now allow hardware interrupts.
200 	 */
201 	{
202 		int msr;
203 
204 		splraise(-1);
205 		__asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
206 			      : "=r"(msr) : "K"(PSL_EE));
207 	}
208 	/*
209 	 * Now safe for bus space allocation to use malloc.
210 	 */
211 	bus_space_mallocok();
212 }
213 
214 /*
215  * lookup_bootinfo:
216  * Look up information in bootinfo of boot loader.
217  */
218 void *
lookup_bootinfo(int type)219 lookup_bootinfo(int type)
220 {
221 	struct btinfo_common *bt;
222 	struct btinfo_common *help = (struct btinfo_common *)bootinfo;
223 
224 	do {
225 		bt = help;
226 		if (bt->type == type)
227 			return (help);
228 		help = (struct btinfo_common *)((char*)help + bt->next);
229 	} while (bt->next &&
230 		(size_t)help < (size_t)bootinfo + sizeof (bootinfo));
231 
232 	return (NULL);
233 }
234 
235 /*
236  * Halt or reboot the machine after syncing/dumping according to howto.
237  */
238 void
cpu_reboot(int howto,char * what)239 cpu_reboot(int howto, char *what)
240 {
241 	static int syncing;
242 
243 	if (cold) {
244 		howto |= RB_HALT;
245 		goto halt_sys;
246 	}
247 
248 	boothowto = howto;
249 	if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
250 		syncing = 1;
251 		vfs_shutdown();		/* sync */
252 	}
253 
254 	/* Disable intr */
255 	splhigh();
256 
257 #ifdef MULTIPROCESSOR
258 	/* Halt other CPUs */
259 	ppc_send_ipi(IPI_T_NOTME, PPC_IPI_HALT);
260 	delay(100000);  /* XXX */
261 #endif
262 
263 	/* Do dump if requested */
264 	if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
265 		oea_dumpsys();
266 
267 halt_sys:
268 	doshutdownhooks();
269 
270 	pmf_system_shutdown(boothowto);
271 
272 	if (howto & RB_HALT) {
273                 printf("\n");
274                 printf("The operating system has halted.\n");
275                 printf("Please press any key to reboot.\n\n");
276                 cnpollc(1);	/* for proper keyboard command handling */
277                 cngetc();
278                 cnpollc(0);
279 	}
280 
281 	printf("rebooting...\n\n");
282 
283 	reset_prep();
284 
285 	for (;;)
286 		continue;
287 	/* NOTREACHED */
288 }
289 
290 struct powerpc_bus_space prep_eisa_io_space_tag = {
291 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
292 	.pbs_offset = 0x80000000,
293 	.pbs_base = 0x00000000,
294 	.pbs_limit = 0x0000f000,
295 };
296 
297 struct powerpc_bus_space prep_eisa_mem_space_tag = {
298 	.pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_MEM_TYPE,
299 	.pbs_offset = 0xC0000000,
300 	.pbs_base = 0x00000000,
301 	.pbs_limit = 0x3f000000,
302 };
303 
304 #if defined(PIC_OPENPIC)
305 
306 static int
prep_setup_openpic(PPC_DEVICE * dev)307 prep_setup_openpic(PPC_DEVICE *dev)
308 {
309 	uint32_t l;
310 	uint8_t *p;
311 	int tag, size, item, i;
312 	unsigned char *baseaddr = NULL;
313 
314 	l = be32toh(dev->AllocatedOffset);
315 	p = res->DevicePnPHeap + l;
316 
317         i = find_platform_quirk(res->VitalProductData.PrintableModel);
318 
319 	/* look for the large vendor item that describes the MPIC's memory
320 	 * range */
321 	for (; p[0] != END_TAG; p += size) {
322 		struct _L4_Pack *pack = (void *)p;
323 		struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
324 
325 		tag = *p;
326 		if (tag_type(p[0]) == PNP_SMALL) {
327 			size = tag_small_count(tag) + 1;
328 			continue;
329 		}
330 		size = (p[1] | (p[2] << 8)) + 3 /* tag + length */;
331 		item = tag_large_item_name(tag);
332 		if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
333 			continue;
334 		/* otherwise, we have a memory packet */
335 		if (pa->PPCData[0] == 1)
336 			baseaddr = (unsigned char *)mapiodev(
337 			    le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_IO,
338 			    le64dec(&pa->PPCData[12]), false);
339 		else if (pa->PPCData[0] == 2)
340 			baseaddr = (unsigned char *)mapiodev(
341 			    le64dec(&pa->PPCData[4]) | PREP_BUS_SPACE_MEM,
342 			    le64dec(&pa->PPCData[12]), false);
343 		if (baseaddr == NULL)
344 			return 0;
345 		pic_init();
346         	if (i != -1 &&
347 		    (platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
348                      platform_quirks[i].isa_intr_handler == EXT_INTR_I8259)) {
349 			isa_pic = setup_prepivr(PIC_IVR_MOT);
350                 } else
351 			isa_pic = setup_prepivr(PIC_IVR_IBM);
352 		(void)setup_openpic(baseaddr, 0);
353 		/* set the timebase frequency to 1/8th busfreq */
354 		openpic_write(OPENPIC_TIMER_FREQ, busfreq/8);
355 		primary_pic = 1;
356 		/* set up the IVR as a cascade on openpic 0 */
357 		intr_establish(16, IST_LEVEL, IPL_HIGH, pic_handle_intr,
358 		    isa_pic);
359 		oea_install_extint(pic_ext_intr);
360 #ifdef MULTIPROCESSOR
361 		setup_openpic_ipi();
362 #endif
363 		return 1;
364 	}
365 	return 0;
366 }
367 
368 #endif /* PIC_OPENPIC */
369 
370 /*
371  * Locate and setup the isa_ivr.
372  */
373 
374 static void
setup_ivr(PPC_DEVICE * dev)375 setup_ivr(PPC_DEVICE *dev)
376 {
377 	uint32_t l, addr;
378 	uint8_t *p;
379 	int tag, size, item;
380 
381 	l = be32toh(dev->AllocatedOffset);
382 	p = res->DevicePnPHeap + l;
383 
384 	/* Find the IVR vector's Generic Address in a LVI */
385 	for (; p[0] != END_TAG; p += size) {
386 		struct _L4_Pack *pack = (void *)p;
387 		struct _L4_PPCPack *pa = &pack->L4_Data.L4_PPCPack;
388 
389 		tag = *p;
390 		if (tag_type(p[0]) == PNP_SMALL) {
391 			size = tag_small_count(tag) + 1;
392 			continue;
393 		}
394 		size = (p[1] | (p[2] << 8)) + 3 /* tag + length */;
395 		item = tag_large_item_name(tag);
396 		if (item != LargeVendorItem || pa->Type != LV_GenericAddress)
397 			continue;
398 		/* otherwise we have a memory packet */
399 		addr = le64dec(&pa->PPCData[4]) & ~(PAGE_SIZE-1);
400 		prep_intr_reg_off = le64dec(&pa->PPCData[4]) & (PAGE_SIZE-1);
401 		prep_intr_reg = (vaddr_t)mapiodev(addr, PAGE_SIZE, false);
402 		if (!prep_intr_reg)
403 			panic("startup: no room for interrupt register");
404 		return;
405 	}
406 }
407 
408 /*
409  * There are a few things that need setting up early on in the prep
410  * architecture.  Foremost of these is the MPIC (if present) and the
411  * l2 cache controller.  This is a cut-down version of pnpbus_search()
412  * that looks for specific devices, and sets them up accordingly.
413  * This should also look for and wire up the interrupt vector.
414  */
415 
416 static void
prep_init(void)417 prep_init(void)
418 {
419 	PPC_DEVICE *ppc_dev;
420 	int i, foundmpic;
421 	uint32_t ndev;
422 
423 	ndev = be32toh(res->ActualNumDevices);
424 	ppc_dev = res->Devices;
425 	foundmpic = 0;
426 	prep_intr_reg = 0;
427 
428 	for (i = 0; i < ((ndev > MAX_DEVICES) ? MAX_DEVICES : ndev); i++) {
429 		if (ppc_dev[i].DeviceId.DevId == 0x41d00000) /* ISA_PIC */
430 			setup_ivr(&ppc_dev[i]);
431 #if defined(PIC_OPENPIC)
432 		if (ppc_dev[i].DeviceId.DevId == 0x244d000d) { /* MPIC */
433 			foundmpic = prep_setup_openpic(&ppc_dev[i]);
434 		}
435 #endif
436 
437 	}
438 	if (!prep_intr_reg) {
439 		/*
440 		 * For some reason we never found one, this is known to
441 		 * occur on certain motorola VME boards.  Instead we need
442 		 * to just hardcode it.
443 		 */
444 		prep_intr_reg = (vaddr_t) mapiodev(PREP_INTR_REG, PAGE_SIZE, false);
445 		if (!prep_intr_reg)
446 			panic("startup: no room for interrupt register");
447 		prep_intr_reg_off = INTR_VECTOR_REG;
448 	}
449 	if (!foundmpic)
450 		init_intr();
451 }
452 
453 static void
init_intr(void)454 init_intr(void)
455 {
456         int i;
457 
458 #if defined(PIC_OPENPIC)
459         openpic_base = 0;
460 #endif
461 
462 	pic_init();
463         i = find_platform_quirk(res->VitalProductData.PrintableModel);
464         if (i != -1)
465                 if (platform_quirks[i].quirk & PLAT_QUIRK_ISA_HANDLER &&
466                     platform_quirks[i].isa_intr_handler == EXT_INTR_I8259) {
467 			isa_pic = setup_prepivr(PIC_IVR_MOT);
468                         return;
469                 }
470 	isa_pic = setup_prepivr(PIC_IVR_IBM);
471         oea_install_extint(pic_ext_intr);
472 }
473