xref: /openbmc/linux/arch/powerpc/boot/oflib.c (revision 2e6016133755eb3cc44e8efab92573d23ed75888)
1*2e601613SDavid Gibson /*
2*2e601613SDavid Gibson  * Copyright (C) Paul Mackerras 1997.
3*2e601613SDavid Gibson  *
4*2e601613SDavid Gibson  * This program is free software; you can redistribute it and/or
5*2e601613SDavid Gibson  * modify it under the terms of the GNU General Public License
6*2e601613SDavid Gibson  * as published by the Free Software Foundation; either version
7*2e601613SDavid Gibson  * 2 of the License, or (at your option) any later version.
8*2e601613SDavid Gibson  */
9*2e601613SDavid Gibson #include <stddef.h>
10*2e601613SDavid Gibson #include "types.h"
11*2e601613SDavid Gibson #include "elf.h"
12*2e601613SDavid Gibson #include "string.h"
13*2e601613SDavid Gibson #include "stdio.h"
14*2e601613SDavid Gibson #include "page.h"
15*2e601613SDavid Gibson #include "ops.h"
16*2e601613SDavid Gibson 
17*2e601613SDavid Gibson #include "of.h"
18*2e601613SDavid Gibson 
19*2e601613SDavid Gibson static int (*prom) (void *);
20*2e601613SDavid Gibson 
21*2e601613SDavid Gibson void of_init(void *promptr)
22*2e601613SDavid Gibson {
23*2e601613SDavid Gibson 	prom = (int (*)(void *))promptr;
24*2e601613SDavid Gibson }
25*2e601613SDavid Gibson 
26*2e601613SDavid Gibson int of_call_prom(const char *service, int nargs, int nret, ...)
27*2e601613SDavid Gibson {
28*2e601613SDavid Gibson 	int i;
29*2e601613SDavid Gibson 	struct prom_args {
30*2e601613SDavid Gibson 		const char *service;
31*2e601613SDavid Gibson 		int nargs;
32*2e601613SDavid Gibson 		int nret;
33*2e601613SDavid Gibson 		unsigned int args[12];
34*2e601613SDavid Gibson 	} args;
35*2e601613SDavid Gibson 	va_list list;
36*2e601613SDavid Gibson 
37*2e601613SDavid Gibson 	args.service = service;
38*2e601613SDavid Gibson 	args.nargs = nargs;
39*2e601613SDavid Gibson 	args.nret = nret;
40*2e601613SDavid Gibson 
41*2e601613SDavid Gibson 	va_start(list, nret);
42*2e601613SDavid Gibson 	for (i = 0; i < nargs; i++)
43*2e601613SDavid Gibson 		args.args[i] = va_arg(list, unsigned int);
44*2e601613SDavid Gibson 	va_end(list);
45*2e601613SDavid Gibson 
46*2e601613SDavid Gibson 	for (i = 0; i < nret; i++)
47*2e601613SDavid Gibson 		args.args[nargs+i] = 0;
48*2e601613SDavid Gibson 
49*2e601613SDavid Gibson 	if (prom(&args) < 0)
50*2e601613SDavid Gibson 		return -1;
51*2e601613SDavid Gibson 
52*2e601613SDavid Gibson 	return (nret > 0)? args.args[nargs]: 0;
53*2e601613SDavid Gibson }
54*2e601613SDavid Gibson 
55*2e601613SDavid Gibson static int of_call_prom_ret(const char *service, int nargs, int nret,
56*2e601613SDavid Gibson 			    unsigned int *rets, ...)
57*2e601613SDavid Gibson {
58*2e601613SDavid Gibson 	int i;
59*2e601613SDavid Gibson 	struct prom_args {
60*2e601613SDavid Gibson 		const char *service;
61*2e601613SDavid Gibson 		int nargs;
62*2e601613SDavid Gibson 		int nret;
63*2e601613SDavid Gibson 		unsigned int args[12];
64*2e601613SDavid Gibson 	} args;
65*2e601613SDavid Gibson 	va_list list;
66*2e601613SDavid Gibson 
67*2e601613SDavid Gibson 	args.service = service;
68*2e601613SDavid Gibson 	args.nargs = nargs;
69*2e601613SDavid Gibson 	args.nret = nret;
70*2e601613SDavid Gibson 
71*2e601613SDavid Gibson 	va_start(list, rets);
72*2e601613SDavid Gibson 	for (i = 0; i < nargs; i++)
73*2e601613SDavid Gibson 		args.args[i] = va_arg(list, unsigned int);
74*2e601613SDavid Gibson 	va_end(list);
75*2e601613SDavid Gibson 
76*2e601613SDavid Gibson 	for (i = 0; i < nret; i++)
77*2e601613SDavid Gibson 		args.args[nargs+i] = 0;
78*2e601613SDavid Gibson 
79*2e601613SDavid Gibson 	if (prom(&args) < 0)
80*2e601613SDavid Gibson 		return -1;
81*2e601613SDavid Gibson 
82*2e601613SDavid Gibson 	if (rets != (void *) 0)
83*2e601613SDavid Gibson 		for (i = 1; i < nret; ++i)
84*2e601613SDavid Gibson 			rets[i-1] = args.args[nargs+i];
85*2e601613SDavid Gibson 
86*2e601613SDavid Gibson 	return (nret > 0)? args.args[nargs]: 0;
87*2e601613SDavid Gibson }
88*2e601613SDavid Gibson 
89*2e601613SDavid Gibson /* returns true if s2 is a prefix of s1 */
90*2e601613SDavid Gibson static int string_match(const char *s1, const char *s2)
91*2e601613SDavid Gibson {
92*2e601613SDavid Gibson 	for (; *s2; ++s2)
93*2e601613SDavid Gibson 		if (*s1++ != *s2)
94*2e601613SDavid Gibson 			return 0;
95*2e601613SDavid Gibson 	return 1;
96*2e601613SDavid Gibson }
97*2e601613SDavid Gibson 
98*2e601613SDavid Gibson /*
99*2e601613SDavid Gibson  * Older OF's require that when claiming a specific range of addresses,
100*2e601613SDavid Gibson  * we claim the physical space in the /memory node and the virtual
101*2e601613SDavid Gibson  * space in the chosen mmu node, and then do a map operation to
102*2e601613SDavid Gibson  * map virtual to physical.
103*2e601613SDavid Gibson  */
104*2e601613SDavid Gibson static int need_map = -1;
105*2e601613SDavid Gibson static ihandle chosen_mmu;
106*2e601613SDavid Gibson static phandle memory;
107*2e601613SDavid Gibson 
108*2e601613SDavid Gibson static int check_of_version(void)
109*2e601613SDavid Gibson {
110*2e601613SDavid Gibson 	phandle oprom, chosen;
111*2e601613SDavid Gibson 	char version[64];
112*2e601613SDavid Gibson 
113*2e601613SDavid Gibson 	oprom = finddevice("/openprom");
114*2e601613SDavid Gibson 	if (oprom == (phandle) -1)
115*2e601613SDavid Gibson 		return 0;
116*2e601613SDavid Gibson 	if (getprop(oprom, "model", version, sizeof(version)) <= 0)
117*2e601613SDavid Gibson 		return 0;
118*2e601613SDavid Gibson 	version[sizeof(version)-1] = 0;
119*2e601613SDavid Gibson 	printf("OF version = '%s'\r\n", version);
120*2e601613SDavid Gibson 	if (!string_match(version, "Open Firmware, 1.")
121*2e601613SDavid Gibson 	    && !string_match(version, "FirmWorks,3."))
122*2e601613SDavid Gibson 		return 0;
123*2e601613SDavid Gibson 	chosen = finddevice("/chosen");
124*2e601613SDavid Gibson 	if (chosen == (phandle) -1) {
125*2e601613SDavid Gibson 		chosen = finddevice("/chosen@0");
126*2e601613SDavid Gibson 		if (chosen == (phandle) -1) {
127*2e601613SDavid Gibson 			printf("no chosen\n");
128*2e601613SDavid Gibson 			return 0;
129*2e601613SDavid Gibson 		}
130*2e601613SDavid Gibson 	}
131*2e601613SDavid Gibson 	if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
132*2e601613SDavid Gibson 		printf("no mmu\n");
133*2e601613SDavid Gibson 		return 0;
134*2e601613SDavid Gibson 	}
135*2e601613SDavid Gibson 	memory = (ihandle) of_call_prom("open", 1, 1, "/memory");
136*2e601613SDavid Gibson 	if (memory == (ihandle) -1) {
137*2e601613SDavid Gibson 		memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0");
138*2e601613SDavid Gibson 		if (memory == (ihandle) -1) {
139*2e601613SDavid Gibson 			printf("no memory node\n");
140*2e601613SDavid Gibson 			return 0;
141*2e601613SDavid Gibson 		}
142*2e601613SDavid Gibson 	}
143*2e601613SDavid Gibson 	printf("old OF detected\r\n");
144*2e601613SDavid Gibson 	return 1;
145*2e601613SDavid Gibson }
146*2e601613SDavid Gibson 
147*2e601613SDavid Gibson void *of_claim(unsigned long virt, unsigned long size, unsigned long align)
148*2e601613SDavid Gibson {
149*2e601613SDavid Gibson 	int ret;
150*2e601613SDavid Gibson 	unsigned int result;
151*2e601613SDavid Gibson 
152*2e601613SDavid Gibson 	if (need_map < 0)
153*2e601613SDavid Gibson 		need_map = check_of_version();
154*2e601613SDavid Gibson 	if (align || !need_map)
155*2e601613SDavid Gibson 		return (void *) of_call_prom("claim", 3, 1, virt, size, align);
156*2e601613SDavid Gibson 
157*2e601613SDavid Gibson 	ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
158*2e601613SDavid Gibson 			       align, size, virt);
159*2e601613SDavid Gibson 	if (ret != 0 || result == -1)
160*2e601613SDavid Gibson 		return (void *) -1;
161*2e601613SDavid Gibson 	ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
162*2e601613SDavid Gibson 			       align, size, virt);
163*2e601613SDavid Gibson 	/* 0x12 == coherent + read/write */
164*2e601613SDavid Gibson 	ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
165*2e601613SDavid Gibson 			   0x12, size, virt, virt);
166*2e601613SDavid Gibson 	return (void *) virt;
167*2e601613SDavid Gibson }
168*2e601613SDavid Gibson 
169*2e601613SDavid Gibson void of_exit(void)
170*2e601613SDavid Gibson {
171*2e601613SDavid Gibson 	of_call_prom("exit", 0, 0);
172*2e601613SDavid Gibson }
173