1 /* $NetBSD: machdep.c,v 1.13 2023/12/20 15:29:06 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.13 2023/12/20 15:29:06 thorpej Exp $");
34
35 #include "opt_compat_netbsd.h"
36 #include "opt_ddb.h"
37 #include "opt_modular.h"
38
39 #include <sys/param.h>
40 #include <sys/buf.h>
41 #include <sys/bus.h>
42 #include <sys/conf.h>
43 #include <sys/device.h>
44 #include <sys/exec.h>
45 #include <sys/extent.h>
46 #include <sys/intr.h>
47 #include <sys/kernel.h>
48 #include <sys/ksyms.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/sysctl.h>
56 #include <sys/syslog.h>
57 #include <sys/systm.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <machine/autoconf.h>
62 #include <machine/bootinfo.h>
63 #include <machine/powerpc.h>
64 #include <machine/iplcb.h>
65
66 #include <powerpc/pmap.h>
67 #include <powerpc/trap.h>
68
69 #include <powerpc/oea/bat.h>
70 #include <powerpc/pio.h>
71 #include <powerpc/pic/picvar.h>
72
73 #include <dev/cons.h>
74
75 #include "com.h"
76 #if (NCOM > 0)
77 #include <sys/termios.h>
78 #include <dev/ic/comreg.h>
79 #include <dev/ic/comvar.h>
80 void comsoft(void);
81 #endif
82
83 #ifdef DDB
84 #include <powerpc/db_machdep.h>
85 #include <ddb/db_extern.h>
86 #endif
87
88 #include "ksyms.h"
89
90 void initppc(u_long, u_long, u_int, void *);
91 void dumpsys(void);
92 void strayintr(int);
93 void rs6000_bus_space_init(void);
94 void setled(uint32_t);
95 void say_hi(void);
96 static void init_intr(void);
97
98 char bootinfo[BOOTINFO_MAXSIZE];
99 char bootpath[256];
100 struct ipl_directory *ipldir;
101 struct ipl_cb *iplcb;
102 struct ipl_info *iplinfo;
103 int led_avail;
104 struct sys_info *sysinfo;
105 struct buc_info *bucinfo[MAX_BUCS];
106 int nrofbucs;
107
108 struct pic_ops *pic_iocc;
109
110 #define OFMEMREGIONS 32
111 struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
112
113 paddr_t avail_end; /* XXX temporary */
114 extern register_t iosrtable[16];
115
116 #if NKSYMS || defined(DDB) || defined(MODULAR)
117 extern void *endsym, *startsym;
118 #endif
119
120 #ifndef CONCOMADDR
121 #define CONCOMADDR 0x30
122 #endif
123
124 #ifndef CONSPEED
125 #define CONSPEED 9600
126 #endif
127
128 #ifndef CONMODE
129 #define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
130 #endif
131
132 int comcnspeed = CONSPEED;
133 int comcnmode = CONMODE;
134 struct consdev kcomcons;
135 static void kcomcnputc(dev_t, int);
136
137 extern struct pic_ops *setup_iocc(void);
138
139
140 void
say_hi(void)141 say_hi(void)
142 {
143 printf("HELLO?!\n");
144 setled(0x55500000);
145 #ifdef DDB
146 Debugger();
147 #endif
148 #if 0
149 li %r28,0x00000041 /* PUT A to R28*/
150 li %r29,0x30 /* put serial addr to r29*/
151 addis %r29,%r29,0xc000 /* r29 now holds serial addr*/
152 stb %r28,0(%r29) /* slam it to serial port*/
153 loopforever:
154 bla loopforever
155 #endif
156 }
157 /*
158 * Set LED's. Yes I know this is ugly. Yes I will rewrite it in pure asm.
159 */
160 void
setled(uint32_t val)161 setled(uint32_t val)
162 {
163 #if 0
164 register_t savemsr, msr, savesr15;
165
166 __asm volatile ("mfmsr %0" : "=r"(savemsr));
167 msr = savemsr & ~PSL_DR;
168 __asm volatile ("mtmsr %0" : : "r"(msr));
169
170 __asm volatile ("mfsr %0,15;isync" : "=r"(savesr15));
171 __asm volatile ("mtsr 15,%0" : : "r"(0x82040080));
172 __asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR));
173 __asm volatile ("isync");
174 *(uint32_t *)0xF0A00300 = val;
175 __asm volatile ("mtmsr %0" : : "r"(savemsr));
176 __asm volatile ("mtsr 15,%0;isync" : : "r"(savesr15));
177 #endif
178 if (led_avail)
179 *(uint32_t *)0xFF600300 = val;
180 }
181
182 #if 0
183 int
184 power_cputype(void)
185 {
186 uint32_t model;
187
188 model = iplinfo->model;
189 if (model & 0x08000000) {
190 /* ppc */
191 return 0;
192 } else if (model & 0x02000000)
193 return POWER_RSC;
194 else if (model & 0x04000000)
195 return POWER_2;
196 else
197 return POWER_1;
198 }
199 #endif
200
201
202 void
initppc(u_long startkernel,u_long endkernel,u_int args,void * btinfo)203 initppc(u_long startkernel, u_long endkernel, u_int args, void *btinfo)
204 {
205 u_long ekern;
206 struct ipl_cb *r_iplcb;
207 struct ipl_directory *r_ipldir;
208 struct buc_info *bi;
209 int i;
210 register_t savemsr, msr;
211
212 /* indicate we have control */
213 //setled(0x40000000);
214 *(uint8_t *)0xe0000030 = '1';
215
216 /* copy bootinfo */
217 memcpy(bootinfo, btinfo, sizeof(bootinfo));
218 *(uint8_t *)0xe0000030 = '2';
219
220 /* copy iplcb data */
221 {
222 struct btinfo_iplcb *iplcbinfo;
223
224 iplcbinfo =
225 (struct btinfo_iplcb *)lookup_bootinfo(BTINFO_IPLCB);
226 if (!iplcbinfo)
227 panic("no iplcb information found in bootinfo");
228
229 /* round_page endkernel, copy down to there, adjust */
230 ekern = round_page(endkernel);
231
232 r_iplcb = (struct ipl_cb *)iplcbinfo->addr;
233 r_ipldir = (struct ipl_directory *)&r_iplcb->dir;
234 memcpy((void *)ekern, r_iplcb, r_ipldir->cb_bitmap_size);
235 iplcb = (struct ipl_cb *)ekern;
236 ipldir = (struct ipl_directory *)&iplcb->dir;
237 iplinfo = (struct ipl_info *)((char *)iplcb +
238 ipldir->iplinfo_off);
239 sysinfo = (struct sys_info *)((char *)iplcb +
240 ipldir->sysinfo_offset);
241
242 ekern += r_ipldir->cb_bitmap_size;
243 endkernel = ekern;
244
245 }
246
247 /* IPLCB copydown successful */
248 setled(0x40100000);
249
250 /* Set memory region */
251 {
252 u_long memsize = iplinfo->ram_size;
253
254 /*
255 * Some machines incorrectly report memory size in
256 * MB. Stupid stupid IBM breaking their own spec.
257 * on conformant machines, it is:
258 * The highest addressable real memory address byte+1
259 */
260 if (memsize < 4069)
261 memsize = memsize * 1024 * 1024;
262 else
263 memsize -= 1;
264 physmemr[0].start = 0;
265 physmemr[0].size = memsize & ~PGOFSET;
266 availmemr[0].start = round_page(endkernel);
267 availmemr[0].size = memsize - availmemr[0].start;
268 }
269 avail_end = physmemr[0].start + physmemr[0].size; /* XXX temporary */
270 *(uint8_t *)0xe0000030 = '3';
271
272 #ifdef NOTYET
273 /* hrmm.. there is no timebase crap on POWER */
274 /*
275 * Set CPU clock
276 */
277 {
278 struct btinfo_clock *clockinfo;
279 extern u_long ticks_per_sec, ns_per_tick;
280
281 clockinfo =
282 (struct btinfo_clock *)lookup_bootinfo(BTINFO_CLOCK);
283 if (!clockinfo)
284 panic("not found clock information in bootinfo");
285
286 ticks_per_sec = clockinfo->ticks_per_sec;
287 ns_per_tick = 1000000000 / ticks_per_sec;
288 }
289 #endif
290 /* boothowto */
291 boothowto = args;
292
293 /*
294 * Now setup fixed bat registers
295 * 1) POWER has no bat registers.
296 * 2) NVRAM, IPL ROM, and other fun bits all live at 0xFF000000 on the
297 * 60x RS6000's, however if you try to map any less than 256MB
298 * on a 601 it wedges.
299 */
300 #if !defined(POWER)
301 setled(0x40200000);
302 oea_batinit(
303 0xF0000000, BAT_BL_256M,
304 /*
305 RS6000_BUS_SPACE_MEM, BAT_BL_256M,
306 RS6000_BUS_SPACE_IO, BAT_BL_256M,
307 0xbf800000, BAT_BL_8M,
308 */
309 0);
310 led_avail = 1;
311 #endif
312 setled(0x40200000);
313
314 /* set the IO segreg for the first IOCC */
315 #ifdef POWER
316 iosrtable[0xc] = 0x820C00E0;
317 #else
318 iosrtable[0xc] = 0x82000080;
319 #endif
320 __asm volatile ("mfmsr %0" : "=r"(savemsr));
321 msr = savemsr & ~PSL_DR;
322 __asm volatile ("mtmsr %0" : : "r"(msr));
323 __asm volatile ("mtsr 0xc,%0" : : "r"(iosrtable[0xc]));
324 __asm volatile ("mtmsr %0" : : "r"(msr|PSL_DR));
325 __asm volatile ("isync");
326 __asm volatile ("mtmsr %0;isync" : : "r"(savemsr));
327
328 cn_tab = &kcomcons;
329 printf("\nNetBSD/rs6000 booting ...\n");
330 setled(0x40300000);
331
332 /* Install vectors and interrupt handler. */
333 oea_init(NULL);
334 setled(0x40400000);
335
336 /* Initialize pmap module. */
337 uvm_md_init();
338 pmap_bootstrap(startkernel, endkernel);
339 setled(0x40500000);
340
341 /* populate the bucinfo stuff now that we can malloc */
342 bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off);
343 nrofbucs = bi->nrof_structs;
344 /*printf("nrof=%d\n", nrofbucs);*/
345 if (nrofbucs > MAX_BUCS)
346 aprint_error("WARNING: increase MAX_BUCS to at least %d\n",
347 nrofbucs);
348 for (i=0; i < nrofbucs && i < MAX_BUCS; i++) {
349 #ifdef DEBUG
350 printf("bi addr= %p\n", &bi);
351 printf("i=%d ssize=%x\n", i, bi->struct_size);
352 #endif
353 bucinfo[i] = bi;
354 bi = (struct buc_info *)((char *)iplcb + ipldir->bucinfo_off +
355 bi->struct_size);
356 }
357 #ifdef DEBUG
358 printf("found %d bucs\n", nrofbucs);
359 for (i=0; i < nrofbucs; i++) {
360 printf("BUC type: %d\n", bucinfo[i]->dev_type);
361 printf("BUC cfg incr: %x\n", bucinfo[i]->cfg_addr_incr);
362 printf("BUC devid reg: %x\n", bucinfo[i]->device_id_reg);
363 printf("BUC iocc?= %d\n", bucinfo[i]->IOCC_flag);
364 printf("BUC location= %x%x%x%x\n", bucinfo[i]->location[0],
365 bucinfo[i]->location[1], bucinfo[i]->location[2],
366 bucinfo[i]->location[3]);
367 }
368 printf("sysinfo scr_addr %p -> %x\n", sysinfo->scr_addr,
369 *sysinfo->scr_addr);
370 #endif
371
372 /* Initialize bus_space. */
373 rs6000_bus_space_init();
374 setled(0x40600000);
375
376 /* Initialize the console */
377 consinit();
378 setled(0x41000000);
379
380 #if NKSYMS || defined(DDB) || defined(MODULAR)
381 ksyms_addsyms_elf((int)((u_long)endsym - (u_long)startsym), startsym, endsym);
382 #endif
383
384 #ifdef DDB
385 if (boothowto & RB_KDB)
386 Debugger();
387 #endif
388 }
389
390 void
mem_regions(struct mem_region ** mem,struct mem_region ** avail)391 mem_regions(struct mem_region **mem, struct mem_region **avail)
392 {
393
394 *mem = physmemr;
395 *avail = availmemr;
396 }
397
398 static void
init_intr(void)399 init_intr(void)
400 {
401 pic_init();
402 pic_iocc = setup_iocc();
403 oea_install_extint(pic_ext_intr);
404 }
405
406 /*
407 * Machine dependent startup code.
408 */
409 void
cpu_startup(void)410 cpu_startup(void)
411 {
412 /* 420 indicates we are entering cpu_startup() */
413 setled(0x42000000);
414 /* Do common startup. */
415 oea_startup("rs6000");
416
417 /*
418 * Inititalize the IOCC interrupt stuff
419 */
420 init_intr();
421
422 /*
423 * Now allow hardware interrupts.
424 */
425 {
426 int msr;
427
428 splraise(-1);
429 __asm volatile ("mfmsr %0; ori %0,%0,%1; mtmsr %0"
430 : "=r"(msr) : "K"(PSL_EE));
431 setled(0x42200000);
432 }
433 /*
434 * Now safe for bus space allocation to use malloc.
435 */
436 bus_space_mallocok();
437 }
438
439 /*
440 * lookup_bootinfo:
441 * Look up information in bootinfo of boot loader.
442 */
443 void *
lookup_bootinfo(int type)444 lookup_bootinfo(int type)
445 {
446 struct btinfo_common *bt;
447 struct btinfo_common *help = (struct btinfo_common *)bootinfo;
448
449 do {
450 bt = help;
451 if (bt->type == type)
452 return (help);
453 help = (struct btinfo_common *)((char*)help + bt->next);
454 } while (bt->next &&
455 (size_t)help < (size_t)bootinfo + sizeof (bootinfo));
456
457 return (NULL);
458 }
459
460 /*
461 * Reboot an RS6K
462 */
463 static void
reset_rs6000(void)464 reset_rs6000(void)
465 {
466 mtmsr(mfmsr() | PSL_IP);
467
468 /* writing anything to the power/reset reg on an rs6k will cause
469 * a soft reboot. Supposedly.
470 */
471 if (sysinfo->prcr_addr)
472 outb(sysinfo->prcr_addr, 0x1);
473 }
474
475 /*
476 * Halt or reboot the machine after syncing/dumping according to howto.
477 */
478 void
cpu_reboot(int howto,char * what)479 cpu_reboot(int howto, char *what)
480 {
481 static int syncing;
482
483 if (cold) {
484 howto |= RB_HALT;
485 goto halt_sys;
486 }
487
488 boothowto = howto;
489 if ((howto & RB_NOSYNC) == 0 && syncing == 0) {
490 syncing = 1;
491 vfs_shutdown(); /* sync */
492 //resettodr(); /* set wall clock */
493 }
494
495 /* Disable intr */
496 splhigh();
497
498 /* Do dump if requested */
499 if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
500 oea_dumpsys();
501
502 halt_sys:
503 doshutdownhooks();
504
505 pmf_system_shutdown(boothowto);
506
507 if (howto & RB_HALT) {
508 printf("\n");
509 printf("The operating system has halted.\n");
510 printf("Please press any key to reboot.\n\n");
511 cnpollc(1); /* for proper keyboard command handling */
512 cngetc();
513 cnpollc(0);
514 }
515
516 printf("rebooting...\n\n");
517
518 reset_rs6000();
519
520 for (;;)
521 continue;
522 /* NOTREACHED */
523 }
524
525 /* The iocc0 mapping is set by init_ppc to 0xC via an iosegreg */
526 struct powerpc_bus_space rs6000_iocc0_io_space_tag = {
527 .pbs_flags = _BUS_SPACE_LITTLE_ENDIAN|_BUS_SPACE_IO_TYPE,
528 .pbs_offset = 0xC0000000,
529 .pbs_base = 0x00000000,
530 .pbs_limit = 0x10000000,
531 };
532
533 static char ex_storage[2][EXTENT_FIXED_STORAGE_SIZE(8)]
534 __attribute__((aligned(8)));
535
536 void
rs6000_bus_space_init(void)537 rs6000_bus_space_init(void)
538 {
539 int error;
540
541 error = bus_space_init(&rs6000_iocc0_io_space_tag, "ioport",
542 ex_storage[0], sizeof(ex_storage[0]));
543 if (error)
544 panic("rs6000_bus_space_init: can't init io tag");
545
546 #if 0
547 error = extent_alloc_region(rs6000_iocc0_io_space_tag.pbs_extent,
548 0x10000, 0x7F0000, EX_NOWAIT);
549 if (error)
550 panic("rs6000_bus_space_init: can't block out reserved I/O"
551 " space 0x10000-0x7fffff: error=%d", error);
552 error = bus_space_init(&prep_mem_space_tag, "iomem",
553 ex_storage[1], sizeof(ex_storage[1]));
554 if (error)
555 panic("prep_bus_space_init: can't init mem tag");
556
557 rs6000_iocc0_io_space_tag.pbs_extent = prep_io_space_tag.pbs_extent;
558 error = bus_space_init(&prep_isa_io_space_tag, "isa-ioport", NULL, 0);
559 if (error)
560 panic("prep_bus_space_init: can't init isa io tag");
561
562 prep_isa_mem_space_tag.pbs_extent = prep_mem_space_tag.pbs_extent;
563 error = bus_space_init(&prep_isa_mem_space_tag, "isa-iomem", NULL, 0);
564 if (error)
565 panic("prep_bus_space_init: can't init isa mem tag");
566 #endif
567 }
568
569 static bus_space_handle_t kcom_base = (bus_space_handle_t) (0xc0000000 + CONCOMADDR);
570 extern void bsw1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v);
571 extern int bsr1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o);
572 #define KCOM_GETBYTE(r) bsr1(0, kcom_base, (r))
573 #define KCOM_PUTBYTE(r,v) bsw1(0, kcom_base, (r), (v))
574
575 static int
kcomcngetc(dev_t dev)576 kcomcngetc(dev_t dev)
577 {
578 int stat, c;
579 register_t msr;
580
581 msr = mfmsr();
582 mtmsr(msr|PSL_DR);
583 __asm volatile ("isync");
584
585 /* block until a character becomes available */
586 while (!ISSET(stat = KCOM_GETBYTE(com_lsr), LSR_RXRDY))
587 ;
588
589 c = KCOM_GETBYTE(com_data);
590 stat = KCOM_GETBYTE(com_iir);
591 mtmsr(msr);
592 __asm volatile ("isync");
593 return c;
594 }
595
596 /*
597 * Console kernel output character routine.
598 */
599 static void
kcomcnputc(dev_t dev,int c)600 kcomcnputc(dev_t dev, int c)
601 {
602 int timo;
603 register_t msr;
604
605 msr = mfmsr();
606 mtmsr(msr|PSL_DR);
607 __asm volatile ("isync");
608 /* wait for any pending transmission to finish */
609 timo = 150000;
610 while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo)
611 continue;
612
613 KCOM_PUTBYTE(com_data, c);
614
615 /* wait for this transmission to complete */
616 timo = 1500000;
617 while (!ISSET(KCOM_GETBYTE(com_lsr), LSR_TXRDY) && --timo)
618 continue;
619 mtmsr(msr);
620 __asm volatile ("isync");
621 }
622
623 static void
kcomcnpollc(dev_t dev,int on)624 kcomcnpollc(dev_t dev, int on)
625 {
626 }
627
628 struct consdev kcomcons = {
629 NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL,
630 NULL, NULL, NODEV, CN_NORMAL
631 };
632