xref: /openbmc/linux/arch/x86/platform/olpc/olpc_dt.c (revision 4800cd83)
1 /*
2  * OLPC-specific OFW device tree support code.
3  *
4  * Paul Mackerras	August 1996.
5  * Copyright (C) 1996-2005 Paul Mackerras.
6  *
7  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
8  *    {engebret|bergner}@us.ibm.com
9  *
10  *  Adapted for sparc by David S. Miller davem@davemloft.net
11  *  Adapted for x86/OLPC by Andres Salomon <dilinger@queued.net>
12  *
13  *      This program is free software; you can redistribute it and/or
14  *      modify it under the terms of the GNU General Public License
15  *      as published by the Free Software Foundation; either version
16  *      2 of the License, or (at your option) any later version.
17  */
18 
19 #include <linux/kernel.h>
20 #include <linux/bootmem.h>
21 #include <linux/of.h>
22 #include <linux/of_pdt.h>
23 #include <asm/olpc_ofw.h>
24 
25 static phandle __init olpc_dt_getsibling(phandle node)
26 {
27 	const void *args[] = { (void *)node };
28 	void *res[] = { &node };
29 
30 	if ((s32)node == -1)
31 		return 0;
32 
33 	if (olpc_ofw("peer", args, res) || (s32)node == -1)
34 		return 0;
35 
36 	return node;
37 }
38 
39 static phandle __init olpc_dt_getchild(phandle node)
40 {
41 	const void *args[] = { (void *)node };
42 	void *res[] = { &node };
43 
44 	if ((s32)node == -1)
45 		return 0;
46 
47 	if (olpc_ofw("child", args, res) || (s32)node == -1) {
48 		pr_err("PROM: %s: fetching child failed!\n", __func__);
49 		return 0;
50 	}
51 
52 	return node;
53 }
54 
55 static int __init olpc_dt_getproplen(phandle node, const char *prop)
56 {
57 	const void *args[] = { (void *)node, prop };
58 	int len;
59 	void *res[] = { &len };
60 
61 	if ((s32)node == -1)
62 		return -1;
63 
64 	if (olpc_ofw("getproplen", args, res)) {
65 		pr_err("PROM: %s: getproplen failed!\n", __func__);
66 		return -1;
67 	}
68 
69 	return len;
70 }
71 
72 static int __init olpc_dt_getproperty(phandle node, const char *prop,
73 		char *buf, int bufsize)
74 {
75 	int plen;
76 
77 	plen = olpc_dt_getproplen(node, prop);
78 	if (plen > bufsize || plen < 1) {
79 		return -1;
80 	} else {
81 		const void *args[] = { (void *)node, prop, buf, (void *)plen };
82 		void *res[] = { &plen };
83 
84 		if (olpc_ofw("getprop", args, res)) {
85 			pr_err("PROM: %s: getprop failed!\n", __func__);
86 			return -1;
87 		}
88 	}
89 
90 	return plen;
91 }
92 
93 static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
94 {
95 	const void *args[] = { (void *)node, prev, buf };
96 	int success;
97 	void *res[] = { &success };
98 
99 	buf[0] = '\0';
100 
101 	if ((s32)node == -1)
102 		return -1;
103 
104 	if (olpc_ofw("nextprop", args, res) || success != 1)
105 		return -1;
106 
107 	return 0;
108 }
109 
110 static int __init olpc_dt_pkg2path(phandle node, char *buf,
111 		const int buflen, int *len)
112 {
113 	const void *args[] = { (void *)node, buf, (void *)buflen };
114 	void *res[] = { len };
115 
116 	if ((s32)node == -1)
117 		return -1;
118 
119 	if (olpc_ofw("package-to-path", args, res) || *len < 1)
120 		return -1;
121 
122 	return 0;
123 }
124 
125 static unsigned int prom_early_allocated __initdata;
126 
127 void * __init prom_early_alloc(unsigned long size)
128 {
129 	static u8 *mem;
130 	static size_t free_mem;
131 	void *res;
132 
133 	if (free_mem < size) {
134 		const size_t chunk_size = max(PAGE_SIZE, size);
135 
136 		/*
137 		 * To mimimize the number of allocations, grab at least
138 		 * PAGE_SIZE of memory (that's an arbitrary choice that's
139 		 * fast enough on the platforms we care about while minimizing
140 		 * wasted bootmem) and hand off chunks of it to callers.
141 		 */
142 		res = alloc_bootmem(chunk_size);
143 		BUG_ON(!res);
144 		prom_early_allocated += chunk_size;
145 		memset(res, 0, chunk_size);
146 		free_mem = chunk_size;
147 		mem = res;
148 	}
149 
150 	/* allocate from the local cache */
151 	free_mem -= size;
152 	res = mem;
153 	mem += size;
154 	return res;
155 }
156 
157 static struct of_pdt_ops prom_olpc_ops __initdata = {
158 	.nextprop = olpc_dt_nextprop,
159 	.getproplen = olpc_dt_getproplen,
160 	.getproperty = olpc_dt_getproperty,
161 	.getchild = olpc_dt_getchild,
162 	.getsibling = olpc_dt_getsibling,
163 	.pkg2path = olpc_dt_pkg2path,
164 };
165 
166 void __init olpc_dt_build_devicetree(void)
167 {
168 	phandle root;
169 
170 	if (!olpc_ofw_is_installed())
171 		return;
172 
173 	root = olpc_dt_getsibling(0);
174 	if (!root) {
175 		pr_err("PROM: unable to get root node from OFW!\n");
176 		return;
177 	}
178 	of_pdt_build_devicetree(root, &prom_olpc_ops);
179 
180 	pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
181 			prom_early_allocated);
182 }
183