197403Sobrien/*	$NetBSD: Locore.c,v 1.3 2005/12/11 12:19:05 christos Exp $	*/
297403Sobrien
397403Sobrien/*
497403Sobrien * Copyright (C) 1995, 1996 Wolfgang Solfrank.
597403Sobrien * Copyright (C) 1995, 1996 TooLs GmbH.
697403Sobrien * All rights reserved.
797403Sobrien *
897403Sobrien * Redistribution and use in source and binary forms, with or without
997403Sobrien * modification, are permitted provided that the following conditions
1097403Sobrien * are met:
1197403Sobrien * 1. Redistributions of source code must retain the above copyright
1297403Sobrien *    notice, this list of conditions and the following disclaimer.
1397403Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1497403Sobrien *    notice, this list of conditions and the following disclaimer in the
1597403Sobrien *    documentation and/or other materials provided with the distribution.
1697403Sobrien * 3. All advertising materials mentioning features or use of this software
1797403Sobrien *    must display the following acknowledgement:
1897403Sobrien *	This product includes software developed by TooLs GmbH.
1997403Sobrien * 4. The name of TooLs GmbH may not be used to endorse or promote products
2097403Sobrien *    derived from this software without specific prior written permission.
2197403Sobrien *
2297403Sobrien * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
2397403Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2497403Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2597403Sobrien * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2697403Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2797403Sobrien * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2897403Sobrien * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2997403Sobrien * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
3097403Sobrien * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
3197403Sobrien * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3297403Sobrien */
3397403Sobrien
3497403Sobrien#include <lib/libsa/stand.h>
3597403Sobrien
3697403Sobrien#include <machine/cpu.h>
3797403Sobrien
3897403Sobrien#include <arm/armreg.h>
3997403Sobrien
4097403Sobrien#include "cache.h"
4197403Sobrien#include "extern.h"
4297403Sobrien#include "openfirm.h"
4397403Sobrien
4497403Sobrienstatic int (*openfirmware_entry)(void *);
4597403Sobrienstatic int openfirmware(void *);
4697403Sobrien
4797403Sobrienvoid startup(int (*)(void *), char *, int);
4897403Sobrienstatic void setup(void);
4997403Sobrien
5097403Sobrienvoid (*cache_syncI)(void);
5197403Sobrien
5297403Sobrienvoid abort(void);
5397403Sobrienvoid abort(void)
5497403Sobrien{
5597403Sobrien
5697403Sobrien	/* Stupid compiler (__dead). */
5797403Sobrien	for (;;)
5897403Sobrien		continue;
5997403Sobrien}
6097403Sobrien
6197403Sobrienstatic int
6297403Sobrienopenfirmware(void *arg)
6397403Sobrien{
6497403Sobrien
6597403Sobrien	(*openfirmware_entry)(arg);
6697403Sobrien	return 0;
6797403Sobrien}
6897403Sobrien
6997403Sobrienstatic vaddr_t
7097403Sobrienofw_getcleaninfo(void)
7197403Sobrien{
7297403Sobrien	int cpu, vclean;
7397403Sobrien
7497403Sobrien	if ((cpu = OF_finddevice("/cpu")) == -1)
7597403Sobrien		panic("no /cpu from OFW");
7697403Sobrien
7797403Sobrien	if (OF_getprop(cpu, "d-cache-flush-address", &vclean,
7897403Sobrien		       sizeof(vclean)) != sizeof(vclean)) {
7997403Sobrien		printf("WARNING: no OFW d-cache-flush-address property\n");
8097403Sobrien		return (RELOC);
8197403Sobrien	}
8297403Sobrien
8397403Sobrien	return (of_decode_int((unsigned char *)&vclean));
8497403Sobrien}
8597403Sobrien
8697403Sobrienvoid
8797403Sobrienstartup(int (*openfirm)(void *), char *arg, int argl)
8897403Sobrien{
8997403Sobrien	u_int cputype = cpufunc_id() & CPU_ID_CPU_MASK;
9097403Sobrien
9197403Sobrien	openfirmware_entry = openfirm;
9297403Sobrien	setup();
9397403Sobrien
9497403Sobrien	/*
9597403Sobrien	 * Determine the CPU type, and set up the appropriate
9697403Sobrien	 * I$ sync routine.
9797403Sobrien	 */
9897403Sobrien	if (cputype == CPU_ID_SA110 || cputype == CPU_ID_SA1100 ||
9997403Sobrien	    cputype == CPU_ID_SA1110) {
10097403Sobrien		extern vaddr_t sa110_cache_clean_addr;
10197403Sobrien		cache_syncI = sa110_cache_syncI;
10297403Sobrien		sa110_cache_clean_addr = ofw_getcleaninfo();
10397403Sobrien	} else {
10497403Sobrien		printf("WARNING: no I$ sync routine for CPU 0x%x\n",
10597403Sobrien		    cputype);
10697403Sobrien	}
10797403Sobrien
10897403Sobrien	main();
10997403Sobrien	OF_exit();
11097403Sobrien}
11197403Sobrien
11297403Sobrienint
11397403Sobrienof_decode_int(const u_char *p)
11497403Sobrien{
11597403Sobrien	unsigned int i = *p++ << 8;
11697403Sobrien	i = (i + *p++) << 8;
11797403Sobrien	i = (i + *p++) << 8;
11897403Sobrien	return (i + *p);
11997403Sobrien}
12097403Sobrien
12197403Sobrien__dead void
12297403SobrienOF_exit(void)
12397403Sobrien{
12497403Sobrien	static struct {
12597403Sobrien		const char *name;
12697403Sobrien		int nargs;
12797403Sobrien		int nreturns;
12897403Sobrien	} args = {
12997403Sobrien		"exit",
13097403Sobrien		0,
13197403Sobrien		0
13297403Sobrien	};
13397403Sobrien
13497403Sobrien	openfirmware(&args);
13597403Sobrien	for (;;);			/* just in case */
13697403Sobrien}
13797403Sobrien
13897403Sobrienint
13997403SobrienOF_finddevice(const char *name)
14097403Sobrien{
14197403Sobrien	static struct {
14297403Sobrien		const char *name;
14397403Sobrien		int nargs;
14497403Sobrien		int nreturns;
14597403Sobrien		const char *device;
14697403Sobrien		int phandle;
14797403Sobrien	} args = {
14897403Sobrien		"finddevice",
14997403Sobrien		1,
15097403Sobrien		1,
15197403Sobrien	};
15297403Sobrien
15397403Sobrien	args.device = name;
15497403Sobrien	if (openfirmware(&args) == -1)
15597403Sobrien		return -1;
15697403Sobrien	return args.phandle;
15797403Sobrien}
15897403Sobrien
15997403Sobrienint
16097403SobrienOF_instance_to_package(int ihandle)
16197403Sobrien{
16297403Sobrien	static struct {
16397403Sobrien		const char *name;
16497403Sobrien		int nargs;
16597403Sobrien		int nreturns;
16697403Sobrien		int ihandle;
16797403Sobrien		int phandle;
16897403Sobrien	} args = {
16997403Sobrien		"instance-to-package",
17097403Sobrien		1,
17197403Sobrien		1,
17297403Sobrien	};
17397403Sobrien
17497403Sobrien	args.ihandle = ihandle;
17597403Sobrien	if (openfirmware(&args) == -1)
17697403Sobrien		return -1;
17797403Sobrien	return args.phandle;
17897403Sobrien}
17997403Sobrien
18097403Sobrienint
18197403SobrienOF_getprop(int handle, const char *prop, void *buf, int buflen)
18297403Sobrien{
18397403Sobrien	static struct {
18497403Sobrien		const char *name;
18597403Sobrien		int nargs;
18697403Sobrien		int nreturns;
18797403Sobrien		int phandle;
18897403Sobrien		const char *prop;
18997403Sobrien		void *buf;
19097403Sobrien		int buflen;
19197403Sobrien		int size;
19297403Sobrien	} args = {
19397403Sobrien		"getprop",
19497403Sobrien		4,
19597403Sobrien		1,
19697403Sobrien	};
19797403Sobrien
19897403Sobrien	args.phandle = handle;
19997403Sobrien	args.prop = prop;
20097403Sobrien	args.buf = buf;
20197403Sobrien	args.buflen = buflen;
20297403Sobrien	if (openfirmware(&args) == -1)
20397403Sobrien		return -1;
20497403Sobrien	return args.size;
20597403Sobrien}
20697403Sobrien
20797403Sobrien#ifdef	__notyet__	/* Has a bug on FirePower */
20897403Sobrienint
20997403SobrienOF_setprop(int handle, const char *prop, void *buf, int len)
21097403Sobrien{
21197403Sobrien	static struct {
21297403Sobrien		const char *name;
21397403Sobrien		int nargs;
21497403Sobrien		int nreturns;
21597403Sobrien		int phandle;
21697403Sobrien		const char *prop;
21797403Sobrien		void *buf;
21897403Sobrien		int len;
21997403Sobrien		int size;
22097403Sobrien	} args = {
22197403Sobrien		"setprop",
22297403Sobrien		4,
22397403Sobrien		1,
22497403Sobrien	};
22597403Sobrien
22697403Sobrien	args.phandle = handle;
22797403Sobrien	args.prop = prop;
22897403Sobrien	args.buf = buf;
22997403Sobrien	args.len = len;
23097403Sobrien	if (openfirmware(&args) == -1)
23197403Sobrien		return -1;
23297403Sobrien	return args.size;
23397403Sobrien}
23497403Sobrien#endif
23597403Sobrien
23697403Sobrienint
23797403SobrienOF_open(char *dname)
23897403Sobrien{
23997403Sobrien	static struct {
24097403Sobrien		const char *name;
24197403Sobrien		int nargs;
24297403Sobrien		int nreturns;
24397403Sobrien		char *dname;
24497403Sobrien		int handle;
24597403Sobrien	} args = {
24697403Sobrien		"open",
24797403Sobrien		1,
24897403Sobrien		1,
24997403Sobrien	};
25097403Sobrien
25197403Sobrien#ifdef OFW_DEBUG
25297403Sobrien	printf("OF_open(%s) -> ", dname);
25397403Sobrien#endif
25497403Sobrien	args.dname = dname;
25597403Sobrien	if (openfirmware(&args) == -1 ||
25697403Sobrien	    args.handle == 0) {
25797403Sobrien#ifdef OFW_DEBUG
25897403Sobrien		printf("lose\n");
25997403Sobrien#endif
26097403Sobrien		return -1;
26197403Sobrien	}
26297403Sobrien#ifdef OFW_DEBUG
26397403Sobrien	printf("%d\n", args.handle);
26497403Sobrien#endif
26597403Sobrien	return args.handle;
26697403Sobrien}
26797403Sobrien
26897403Sobrienvoid
26997403SobrienOF_close(int handle)
27097403Sobrien{
27197403Sobrien	static struct {
27297403Sobrien		const char *name;
27397403Sobrien		int nargs;
27497403Sobrien		int nreturns;
27597403Sobrien		int handle;
27697403Sobrien	} args = {
27797403Sobrien		"close",
27897403Sobrien		1,
27997403Sobrien		0,
28097403Sobrien	};
28197403Sobrien
28297403Sobrien#ifdef OFW_DEBUG
28397403Sobrien	printf("OF_close(%d)\n", handle);
28497403Sobrien#endif
28597403Sobrien	args.handle = handle;
28697403Sobrien	openfirmware(&args);
28797403Sobrien}
28897403Sobrien
28997403Sobrienint
29097403SobrienOF_write(int handle, void *addr, int len)
29197403Sobrien{
29297403Sobrien	static struct {
29397403Sobrien		const char *name;
29497403Sobrien		int nargs;
29597403Sobrien		int nreturns;
29697403Sobrien		int ihandle;
29797403Sobrien		void *addr;
29897403Sobrien		int len;
29997403Sobrien		int actual;
30097403Sobrien	} args = {
30197403Sobrien		"write",
30297403Sobrien		3,
30397403Sobrien		1,
30497403Sobrien	};
30597403Sobrien
30697403Sobrien#ifdef OFW_DEBUG
30797403Sobrien	if (len != 1)
30897403Sobrien		printf("OF_write(%d, %x, %x) -> ", handle, addr, len);
30997403Sobrien#endif
31097403Sobrien	args.ihandle = handle;
31197403Sobrien	args.addr = addr;
31297403Sobrien	args.len = len;
31397403Sobrien	if (openfirmware(&args) == -1) {
31497403Sobrien#ifdef OFW_DEBUG
31597403Sobrien		printf("lose\n");
31697403Sobrien#endif
31797403Sobrien		return -1;
31897403Sobrien	}
31997403Sobrien#ifdef OFW_DEBUG
32097403Sobrien	if (len != 1)
32197403Sobrien		printf("%x\n", args.actual);
32297403Sobrien#endif
32397403Sobrien	return args.actual;
32497403Sobrien}
32597403Sobrien
32697403Sobrienint
32797403SobrienOF_read(int handle, void *addr, int len)
32897403Sobrien{
32997403Sobrien	static struct {
33097403Sobrien		const char *name;
33197403Sobrien		int nargs;
33297403Sobrien		int nreturns;
33397403Sobrien		int ihandle;
33497403Sobrien		void *addr;
33597403Sobrien		int len;
33697403Sobrien		int actual;
33797403Sobrien	} args = {
33897403Sobrien		"read",
33997403Sobrien		3,
34097403Sobrien		1,
34197403Sobrien	};
34297403Sobrien
34397403Sobrien#ifdef OFW_DEBUG
34497403Sobrien	if (len != 1)
34597403Sobrien		printf("OF_read(%d, %x, %x) -> ", handle, addr, len);
34697403Sobrien#endif
34797403Sobrien	args.ihandle = handle;
34897403Sobrien	args.addr = addr;
34997403Sobrien	args.len = len;
35097403Sobrien	if (openfirmware(&args) == -1) {
35197403Sobrien#ifdef OFW_DEBUG
35297403Sobrien		printf("lose\n");
35397403Sobrien#endif
35497403Sobrien		return -1;
35597403Sobrien	}
35697403Sobrien#ifdef OFW_DEBUG
35797403Sobrien	if (len != 1)
35897403Sobrien		printf("%x\n", args.actual);
35997403Sobrien#endif
36097403Sobrien	return args.actual;
36197403Sobrien}
36297403Sobrien
36397403Sobrienint
36497403SobrienOF_seek(int handle, u_quad_t pos)
36597403Sobrien{
36697403Sobrien	static struct {
36797403Sobrien		const char *name;
36897403Sobrien		int nargs;
36997403Sobrien		int nreturns;
37097403Sobrien		int handle;
37197403Sobrien		int poshi;
37297403Sobrien		int poslo;
37397403Sobrien		int status;
37497403Sobrien	} args = {
37597403Sobrien		"seek",
37697403Sobrien		3,
37797403Sobrien		1,
37897403Sobrien	};
37997403Sobrien
38097403Sobrien#ifdef OFW_DEBUG
38197403Sobrien	printf("OF_seek(%d, %x, %x) -> ", handle, (int)(pos >> 32), (int)pos);
38297403Sobrien#endif
38397403Sobrien	args.handle = handle;
38497403Sobrien	args.poshi = (int)(pos >> 32);
38597403Sobrien	args.poslo = (int)pos;
38697403Sobrien	if (openfirmware(&args) == -1) {
38797403Sobrien#ifdef OFW_DEBUG
38897403Sobrien		printf("lose\n");
38997403Sobrien#endif
39097403Sobrien		return -1;
39197403Sobrien	}
39297403Sobrien#ifdef OFW_DEBUG
39397403Sobrien	printf("%d\n", args.status);
39497403Sobrien#endif
39597403Sobrien	return args.status;
39697403Sobrien}
39797403Sobrien
39897403Sobrienvoid *
39997403SobrienOF_claim(void *virt, u_int size, u_int align)
40097403Sobrien{
40197403Sobrien	static struct {
40297403Sobrien		const char *name;
40397403Sobrien		int nargs;
40497403Sobrien		int nreturns;
40597403Sobrien		void *virt;
40697403Sobrien		u_int size;
40797403Sobrien		u_int align;
40897403Sobrien		void *baseaddr;
40997403Sobrien	} args = {
41097403Sobrien		"claim",
41197403Sobrien		3,
41297403Sobrien		1,
41397403Sobrien	};
41497403Sobrien
41597403Sobrien#ifdef OFW_DEBUG
41697403Sobrien	printf("OF_claim(%x, %x, %x) -> ", virt, size, align);
41797403Sobrien#endif
41897403Sobrien	args.virt = virt;
41997403Sobrien	args.size = size;
42097403Sobrien	args.align = align;
42197403Sobrien	if (openfirmware(&args) == -1) {
42297403Sobrien#ifdef OFW_DEBUG
42397403Sobrien		printf("lose\n");
42497403Sobrien#endif
42597403Sobrien		return (void *)-1;
42697403Sobrien	}
42797403Sobrien#ifdef OFW_DEBUG
42897403Sobrien	printf("%x\n", args.baseaddr);
42997403Sobrien#endif
43097403Sobrien	return args.baseaddr;
43197403Sobrien}
43297403Sobrien
43397403Sobrienvoid
43497403SobrienOF_release(void *virt, u_int size)
43597403Sobrien{
43697403Sobrien	static struct {
43797403Sobrien		const char *name;
43897403Sobrien		int nargs;
43997403Sobrien		int nreturns;
44097403Sobrien		void *virt;
44197403Sobrien		u_int size;
44297403Sobrien	} args = {
44397403Sobrien		"release",
44497403Sobrien		2,
44597403Sobrien		0,
44697403Sobrien	};
44797403Sobrien
44897403Sobrien#ifdef OFW_DEBUG
44997403Sobrien	printf("OF_release(%x, %x)\n", virt, size);
45097403Sobrien#endif
45197403Sobrien	args.virt = virt;
45297403Sobrien	args.size = size;
45397403Sobrien	openfirmware(&args);
45497403Sobrien}
45597403Sobrien
45697403Sobrienint
45797403SobrienOF_milliseconds(void)
45897403Sobrien{
45997403Sobrien	static struct {
46097403Sobrien		const char *name;
46197403Sobrien		int nargs;
46297403Sobrien		int nreturns;
46397403Sobrien		int ms;
46497403Sobrien	} args = {
46597403Sobrien		"milliseconds",
46697403Sobrien		0,
46797403Sobrien		1,
46897403Sobrien	};
46997403Sobrien
47097403Sobrien	openfirmware(&args);
47197403Sobrien	return args.ms;
47297403Sobrien}
47397403Sobrien
47497403Sobrienvoid
47597403SobrienOF_chain(void *virt, u_int size, void (*entry)(int (*)(void *), void *, u_int),
47697403Sobrien    void *arg, u_int len)
47797403Sobrien{
47897403Sobrien	struct {
47997403Sobrien		const char *name;
48097403Sobrien		int nargs;
48197403Sobrien		int nreturns;
48297403Sobrien		void *virt;
48397403Sobrien		u_int size;
48497403Sobrien		void (*entry)(int (*)(void *), void *, u_int);
48597403Sobrien		void *arg;
48697403Sobrien		u_int len;
48797403Sobrien	} args;
48897403Sobrien
48997403Sobrien	args.name = "chain";
49097403Sobrien	args.nargs = 5;
49197403Sobrien	args.nreturns = 0;
49297403Sobrien	args.virt = virt;
49397403Sobrien	args.size = size;
49497403Sobrien	args.entry = entry;
49597403Sobrien	args.arg = arg;
49697403Sobrien	args.len = len;
49797403Sobrien#if 1
49897403Sobrien	openfirmware(&args);
49997403Sobrien#else
50097403Sobrien	entry(openfirmware_entry, arg, len);
50197403Sobrien#endif
50297403Sobrien}
50397403Sobrien
50497403Sobrienstatic int stdin;
50597403Sobrienstatic int stdout;
50697403Sobrien
50797403Sobrienstatic void
50897403Sobriensetup(void)
50997403Sobrien{
51097403Sobrien	u_char buf[sizeof(int)];
51197403Sobrien	int chosen;
51297403Sobrien
51397403Sobrien	if ((chosen = OF_finddevice("/chosen")) == -1)
51497403Sobrien		OF_exit();
51597403Sobrien
51697403Sobrien	if (OF_getprop(chosen, "stdin", buf, sizeof(buf)) != sizeof(buf))
51797403Sobrien		OF_exit();
51897403Sobrien	stdin = of_decode_int(buf);
51997403Sobrien
52097403Sobrien	if (OF_getprop(chosen, "stdout", buf, sizeof(buf)) != sizeof(buf))
52197403Sobrien		OF_exit();
52297403Sobrien	stdout = of_decode_int(buf);
52397403Sobrien}
52497403Sobrien
52597403Sobrienvoid
52697403Sobrienputchar(int c)
52797403Sobrien{
52897403Sobrien	char ch = c;
52997403Sobrien
53097403Sobrien	if (c == '\n')
53197403Sobrien		putchar('\r');
53297403Sobrien	OF_write(stdout, &ch, 1);
53397403Sobrien}
53497403Sobrien
53597403Sobrienint
53697403Sobriengetchar(void)
53797403Sobrien{
53897403Sobrien	unsigned char ch = '\0';
53997403Sobrien	int l;
54097403Sobrien
54197403Sobrien	while ((l = OF_read(stdin, &ch, 1)) != 1)
54297403Sobrien		if (l != -2 && l != 0)
54397403Sobrien			return -1;
54497403Sobrien	return ch;
54597403Sobrien}
54697403Sobrien