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