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