~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/platform/olpc/olpc_dt.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * OLPC-specific OFW device tree support code.
  4  *
  5  * Paul Mackerras       August 1996.
  6  * Copyright (C) 1996-2005 Paul Mackerras.
  7  *
  8  *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
  9  *    {engebret|bergner}@us.ibm.com
 10  *
 11  *  Adapted for sparc by David S. Miller davem@davemloft.net
 12  *  Adapted for x86/OLPC by Andres Salomon <dilinger@queued.net>
 13  */
 14 
 15 #include <linux/kernel.h>
 16 #include <linux/memblock.h>
 17 #include <linux/of.h>
 18 #include <linux/of_pdt.h>
 19 #include <asm/olpc.h>
 20 #include <asm/olpc_ofw.h>
 21 
 22 static phandle __init olpc_dt_getsibling(phandle node)
 23 {
 24         const void *args[] = { (void *)node };
 25         void *res[] = { &node };
 26 
 27         if ((s32)node == -1)
 28                 return 0;
 29 
 30         if (olpc_ofw("peer", args, res) || (s32)node == -1)
 31                 return 0;
 32 
 33         return node;
 34 }
 35 
 36 static phandle __init olpc_dt_getchild(phandle node)
 37 {
 38         const void *args[] = { (void *)node };
 39         void *res[] = { &node };
 40 
 41         if ((s32)node == -1)
 42                 return 0;
 43 
 44         if (olpc_ofw("child", args, res) || (s32)node == -1) {
 45                 pr_err("PROM: %s: fetching child failed!\n", __func__);
 46                 return 0;
 47         }
 48 
 49         return node;
 50 }
 51 
 52 static int __init olpc_dt_getproplen(phandle node, const char *prop)
 53 {
 54         const void *args[] = { (void *)node, prop };
 55         int len;
 56         void *res[] = { &len };
 57 
 58         if ((s32)node == -1)
 59                 return -1;
 60 
 61         if (olpc_ofw("getproplen", args, res)) {
 62                 pr_err("PROM: %s: getproplen failed!\n", __func__);
 63                 return -1;
 64         }
 65 
 66         return len;
 67 }
 68 
 69 static int __init olpc_dt_getproperty(phandle node, const char *prop,
 70                 char *buf, int bufsize)
 71 {
 72         int plen;
 73 
 74         plen = olpc_dt_getproplen(node, prop);
 75         if (plen > bufsize || plen < 1) {
 76                 return -1;
 77         } else {
 78                 const void *args[] = { (void *)node, prop, buf, (void *)plen };
 79                 void *res[] = { &plen };
 80 
 81                 if (olpc_ofw("getprop", args, res)) {
 82                         pr_err("PROM: %s: getprop failed!\n", __func__);
 83                         return -1;
 84                 }
 85         }
 86 
 87         return plen;
 88 }
 89 
 90 static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
 91 {
 92         const void *args[] = { (void *)node, prev, buf };
 93         int success;
 94         void *res[] = { &success };
 95 
 96         buf[0] = '\0';
 97 
 98         if ((s32)node == -1)
 99                 return -1;
100 
101         if (olpc_ofw("nextprop", args, res) || success != 1)
102                 return -1;
103 
104         return 0;
105 }
106 
107 static int __init olpc_dt_pkg2path(phandle node, char *buf,
108                 const int buflen, int *len)
109 {
110         const void *args[] = { (void *)node, buf, (void *)buflen };
111         void *res[] = { len };
112 
113         if ((s32)node == -1)
114                 return -1;
115 
116         if (olpc_ofw("package-to-path", args, res) || *len < 1)
117                 return -1;
118 
119         return 0;
120 }
121 
122 static unsigned int prom_early_allocated __initdata;
123 
124 void * __init prom_early_alloc(unsigned long size)
125 {
126         static u8 *mem;
127         static size_t free_mem;
128         void *res;
129 
130         if (free_mem < size) {
131                 const size_t chunk_size = max(PAGE_SIZE, size);
132 
133                 /*
134                  * To minimize the number of allocations, grab at least
135                  * PAGE_SIZE of memory (that's an arbitrary choice that's
136                  * fast enough on the platforms we care about while minimizing
137                  * wasted bootmem) and hand off chunks of it to callers.
138                  */
139                 res = memblock_alloc(chunk_size, SMP_CACHE_BYTES);
140                 if (!res)
141                         panic("%s: Failed to allocate %zu bytes\n", __func__,
142                               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 static phandle __init olpc_dt_finddevice(const char *path)
167 {
168         phandle node;
169         const void *args[] = { path };
170         void *res[] = { &node };
171 
172         if (olpc_ofw("finddevice", args, res)) {
173                 pr_err("olpc_dt: finddevice failed!\n");
174                 return 0;
175         }
176 
177         if ((s32) node == -1)
178                 return 0;
179 
180         return node;
181 }
182 
183 static int __init olpc_dt_interpret(const char *words)
184 {
185         int result;
186         const void *args[] = { words };
187         void *res[] = { &result };
188 
189         if (olpc_ofw("interpret", args, res)) {
190                 pr_err("olpc_dt: interpret failed!\n");
191                 return -1;
192         }
193 
194         return result;
195 }
196 
197 /*
198  * Extract board revision directly from OFW device tree.
199  * We can't use olpc_platform_info because that hasn't been set up yet.
200  */
201 static u32 __init olpc_dt_get_board_revision(void)
202 {
203         phandle node;
204         __be32 rev;
205         int r;
206 
207         node = olpc_dt_finddevice("/");
208         if (!node)
209                 return 0;
210 
211         r = olpc_dt_getproperty(node, "board-revision-int",
212                                 (char *) &rev, sizeof(rev));
213         if (r < 0)
214                 return 0;
215 
216         return be32_to_cpu(rev);
217 }
218 
219 static int __init olpc_dt_compatible_match(phandle node, const char *compat)
220 {
221         char buf[64], *p;
222         int plen, len;
223 
224         plen = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
225         if (plen <= 0)
226                 return 0;
227 
228         len = strlen(compat);
229         for (p = buf; p < buf + plen; p += strlen(p) + 1) {
230                 if (strcmp(p, compat) == 0)
231                         return 1;
232         }
233 
234         return 0;
235 }
236 
237 static void __init olpc_dt_fixup(void)
238 {
239         phandle node;
240         u32 board_rev;
241 
242         node = olpc_dt_finddevice("/battery@0");
243         if (!node)
244                 return;
245 
246         board_rev = olpc_dt_get_board_revision();
247         if (!board_rev)
248                 return;
249 
250         if (board_rev >= olpc_board_pre(0xd0)) {
251                 /* XO-1.5 */
252 
253                 if (olpc_dt_compatible_match(node, "olpc,xo1.5-battery"))
254                         return;
255 
256                 /* Add olpc,xo1.5-battery compatible marker to battery node */
257                 olpc_dt_interpret("\" /battery@0\" find-device");
258                 olpc_dt_interpret("  \" olpc,xo1.5-battery\" +compatible");
259                 olpc_dt_interpret("device-end");
260 
261                 if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
262                         /*
263                          * If we have a olpc,xo1-battery compatible, then we're
264                          * running a new enough firmware that already has
265                          * the dcon node.
266                          */
267                         return;
268                 }
269 
270                 /* Add dcon device */
271                 olpc_dt_interpret("\" /pci/display@1\" find-device");
272                 olpc_dt_interpret("  new-device");
273                 olpc_dt_interpret("    \" dcon\" device-name");
274                 olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
275                 olpc_dt_interpret("  finish-device");
276                 olpc_dt_interpret("device-end");
277         } else {
278                 /* XO-1 */
279 
280                 if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
281                         /*
282                          * If we have a olpc,xo1-battery compatible, then we're
283                          * running a new enough firmware that already has
284                          * the dcon and RTC nodes.
285                          */
286                         return;
287                 }
288 
289                 /* Add dcon device, mark RTC as olpc,xo1-rtc */
290                 olpc_dt_interpret("\" /pci/display@1,1\" find-device");
291                 olpc_dt_interpret("  new-device");
292                 olpc_dt_interpret("    \" dcon\" device-name");
293                 olpc_dt_interpret("    \" olpc,xo1-dcon\" +compatible");
294                 olpc_dt_interpret("  finish-device");
295                 olpc_dt_interpret("device-end");
296 
297                 olpc_dt_interpret("\" /rtc\" find-device");
298                 olpc_dt_interpret(" \" olpc,xo1-rtc\" +compatible");
299                 olpc_dt_interpret("device-end");
300         }
301 
302         /* Add olpc,xo1-battery compatible marker to battery node */
303         olpc_dt_interpret("\" /battery@0\" find-device");
304         olpc_dt_interpret("  \" olpc,xo1-battery\" +compatible");
305         olpc_dt_interpret("device-end");
306 }
307 
308 void __init olpc_dt_build_devicetree(void)
309 {
310         phandle root;
311 
312         if (!olpc_ofw_is_installed())
313                 return;
314 
315         olpc_dt_fixup();
316 
317         root = olpc_dt_getsibling(0);
318         if (!root) {
319                 pr_err("PROM: unable to get root node from OFW!\n");
320                 return;
321         }
322         of_pdt_build_devicetree(root, &prom_olpc_ops);
323 
324         pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
325                         prom_early_allocated);
326 }
327 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php