1/*	$NetBSD: machdep.c,v 1.9 2011/06/15 05:50:49 matt 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.9 2011/06/15 05:50:49 matt 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>
81void 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
91void initppc(u_long, u_long, u_int, void *);
92void dumpsys(void);
93void strayintr(int);
94void rs6000_bus_space_init(void);
95void setled(uint32_t);
96void say_hi(void);
97static void init_intr(void);
98
99char bootinfo[BOOTINFO_MAXSIZE];
100char bootpath[256];
101struct ipl_directory	*ipldir;
102struct ipl_cb		*iplcb;
103struct ipl_info		*iplinfo;
104int led_avail;
105struct sys_info		*sysinfo;
106struct buc_info		*bucinfo[MAX_BUCS];
107int nrofbucs;
108
109struct pic_ops *pic_iocc;
110
111#define	OFMEMREGIONS	32
112struct mem_region physmemr[OFMEMREGIONS], availmemr[OFMEMREGIONS];
113
114paddr_t avail_end;			/* XXX temporary */
115extern register_t iosrtable[16];
116
117#if NKSYMS || defined(DDB) || defined(MODULAR)
118extern 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
133int comcnspeed = CONSPEED;
134int comcnmode = CONMODE;
135struct consdev kcomcons;
136static void kcomcnputc(dev_t, int);
137
138extern struct pic_ops *setup_iocc(void);
139
140
141void
142say_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*/
154loopforever:
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 */
161void
162setled(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
184int
185power_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
203void
204initppc(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 thier 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_setpagesize();
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
391void
392mem_regions(struct mem_region **mem, struct mem_region **avail)
393{
394
395	*mem = physmemr;
396	*avail = availmemr;
397}
398
399static void
400init_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 */
410void
411cpu_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 */
444void *
445lookup_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 */
464static void
465reset_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 */
479void
480cpu_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
503halt_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 */
527struct 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
534static char ex_storage[2][EXTENT_FIXED_STORAGE_SIZE(8)]
535    __attribute__((aligned(8)));
536
537void
538rs6000_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
570static bus_space_handle_t kcom_base = (bus_space_handle_t) (0xc0000000 + CONCOMADDR);
571extern void bsw1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o, u_int8_t v);
572extern 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
576static int
577kcomcngetc(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 */
600static void
601kcomcnputc(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
624static void
625kcomcnpollc(dev_t dev, int on)
626{
627}
628
629struct consdev kcomcons = {
630        NULL, NULL, kcomcngetc, kcomcnputc, kcomcnpollc, NULL,
631        NULL, NULL, NODEV, CN_NORMAL
632};
633