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