root/arch/x86/platform/olpc/olpc_dt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. olpc_dt_getsibling
  2. olpc_dt_getchild
  3. olpc_dt_getproplen
  4. olpc_dt_getproperty
  5. olpc_dt_nextprop
  6. olpc_dt_pkg2path
  7. prom_early_alloc
  8. olpc_dt_finddevice
  9. olpc_dt_interpret
  10. olpc_dt_get_board_revision
  11. olpc_dt_compatible_match
  12. olpc_dt_fixup
  13. olpc_dt_build_devicetree

   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 mimimize 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 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 }

/* [<][>][^][v][top][bottom][index][help] */