0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/kernel.h>
0016 #include <linux/memblock.h>
0017 #include <linux/of.h>
0018 #include <linux/of_pdt.h>
0019 #include <asm/olpc.h>
0020 #include <asm/olpc_ofw.h>
0021
0022 static phandle __init olpc_dt_getsibling(phandle node)
0023 {
0024 const void *args[] = { (void *)node };
0025 void *res[] = { &node };
0026
0027 if ((s32)node == -1)
0028 return 0;
0029
0030 if (olpc_ofw("peer", args, res) || (s32)node == -1)
0031 return 0;
0032
0033 return node;
0034 }
0035
0036 static phandle __init olpc_dt_getchild(phandle node)
0037 {
0038 const void *args[] = { (void *)node };
0039 void *res[] = { &node };
0040
0041 if ((s32)node == -1)
0042 return 0;
0043
0044 if (olpc_ofw("child", args, res) || (s32)node == -1) {
0045 pr_err("PROM: %s: fetching child failed!\n", __func__);
0046 return 0;
0047 }
0048
0049 return node;
0050 }
0051
0052 static int __init olpc_dt_getproplen(phandle node, const char *prop)
0053 {
0054 const void *args[] = { (void *)node, prop };
0055 int len;
0056 void *res[] = { &len };
0057
0058 if ((s32)node == -1)
0059 return -1;
0060
0061 if (olpc_ofw("getproplen", args, res)) {
0062 pr_err("PROM: %s: getproplen failed!\n", __func__);
0063 return -1;
0064 }
0065
0066 return len;
0067 }
0068
0069 static int __init olpc_dt_getproperty(phandle node, const char *prop,
0070 char *buf, int bufsize)
0071 {
0072 int plen;
0073
0074 plen = olpc_dt_getproplen(node, prop);
0075 if (plen > bufsize || plen < 1) {
0076 return -1;
0077 } else {
0078 const void *args[] = { (void *)node, prop, buf, (void *)plen };
0079 void *res[] = { &plen };
0080
0081 if (olpc_ofw("getprop", args, res)) {
0082 pr_err("PROM: %s: getprop failed!\n", __func__);
0083 return -1;
0084 }
0085 }
0086
0087 return plen;
0088 }
0089
0090 static int __init olpc_dt_nextprop(phandle node, char *prev, char *buf)
0091 {
0092 const void *args[] = { (void *)node, prev, buf };
0093 int success;
0094 void *res[] = { &success };
0095
0096 buf[0] = '\0';
0097
0098 if ((s32)node == -1)
0099 return -1;
0100
0101 if (olpc_ofw("nextprop", args, res) || success != 1)
0102 return -1;
0103
0104 return 0;
0105 }
0106
0107 static int __init olpc_dt_pkg2path(phandle node, char *buf,
0108 const int buflen, int *len)
0109 {
0110 const void *args[] = { (void *)node, buf, (void *)buflen };
0111 void *res[] = { len };
0112
0113 if ((s32)node == -1)
0114 return -1;
0115
0116 if (olpc_ofw("package-to-path", args, res) || *len < 1)
0117 return -1;
0118
0119 return 0;
0120 }
0121
0122 static unsigned int prom_early_allocated __initdata;
0123
0124 void * __init prom_early_alloc(unsigned long size)
0125 {
0126 static u8 *mem;
0127 static size_t free_mem;
0128 void *res;
0129
0130 if (free_mem < size) {
0131 const size_t chunk_size = max(PAGE_SIZE, size);
0132
0133
0134
0135
0136
0137
0138
0139 res = memblock_alloc(chunk_size, SMP_CACHE_BYTES);
0140 if (!res)
0141 panic("%s: Failed to allocate %zu bytes\n", __func__,
0142 chunk_size);
0143 BUG_ON(!res);
0144 prom_early_allocated += chunk_size;
0145 memset(res, 0, chunk_size);
0146 free_mem = chunk_size;
0147 mem = res;
0148 }
0149
0150
0151 free_mem -= size;
0152 res = mem;
0153 mem += size;
0154 return res;
0155 }
0156
0157 static struct of_pdt_ops prom_olpc_ops __initdata = {
0158 .nextprop = olpc_dt_nextprop,
0159 .getproplen = olpc_dt_getproplen,
0160 .getproperty = olpc_dt_getproperty,
0161 .getchild = olpc_dt_getchild,
0162 .getsibling = olpc_dt_getsibling,
0163 .pkg2path = olpc_dt_pkg2path,
0164 };
0165
0166 static phandle __init olpc_dt_finddevice(const char *path)
0167 {
0168 phandle node;
0169 const void *args[] = { path };
0170 void *res[] = { &node };
0171
0172 if (olpc_ofw("finddevice", args, res)) {
0173 pr_err("olpc_dt: finddevice failed!\n");
0174 return 0;
0175 }
0176
0177 if ((s32) node == -1)
0178 return 0;
0179
0180 return node;
0181 }
0182
0183 static int __init olpc_dt_interpret(const char *words)
0184 {
0185 int result;
0186 const void *args[] = { words };
0187 void *res[] = { &result };
0188
0189 if (olpc_ofw("interpret", args, res)) {
0190 pr_err("olpc_dt: interpret failed!\n");
0191 return -1;
0192 }
0193
0194 return result;
0195 }
0196
0197
0198
0199
0200
0201 static u32 __init olpc_dt_get_board_revision(void)
0202 {
0203 phandle node;
0204 __be32 rev;
0205 int r;
0206
0207 node = olpc_dt_finddevice("/");
0208 if (!node)
0209 return 0;
0210
0211 r = olpc_dt_getproperty(node, "board-revision-int",
0212 (char *) &rev, sizeof(rev));
0213 if (r < 0)
0214 return 0;
0215
0216 return be32_to_cpu(rev);
0217 }
0218
0219 static int __init olpc_dt_compatible_match(phandle node, const char *compat)
0220 {
0221 char buf[64], *p;
0222 int plen, len;
0223
0224 plen = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
0225 if (plen <= 0)
0226 return 0;
0227
0228 len = strlen(compat);
0229 for (p = buf; p < buf + plen; p += strlen(p) + 1) {
0230 if (strcmp(p, compat) == 0)
0231 return 1;
0232 }
0233
0234 return 0;
0235 }
0236
0237 void __init olpc_dt_fixup(void)
0238 {
0239 phandle node;
0240 u32 board_rev;
0241
0242 node = olpc_dt_finddevice("/battery@0");
0243 if (!node)
0244 return;
0245
0246 board_rev = olpc_dt_get_board_revision();
0247 if (!board_rev)
0248 return;
0249
0250 if (board_rev >= olpc_board_pre(0xd0)) {
0251
0252
0253 if (olpc_dt_compatible_match(node, "olpc,xo1.5-battery"))
0254 return;
0255
0256
0257 olpc_dt_interpret("\" /battery@0\" find-device");
0258 olpc_dt_interpret(" \" olpc,xo1.5-battery\" +compatible");
0259 olpc_dt_interpret("device-end");
0260
0261 if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
0262
0263
0264
0265
0266
0267 return;
0268 }
0269
0270
0271 olpc_dt_interpret("\" /pci/display@1\" find-device");
0272 olpc_dt_interpret(" new-device");
0273 olpc_dt_interpret(" \" dcon\" device-name");
0274 olpc_dt_interpret(" \" olpc,xo1-dcon\" +compatible");
0275 olpc_dt_interpret(" finish-device");
0276 olpc_dt_interpret("device-end");
0277 } else {
0278
0279
0280 if (olpc_dt_compatible_match(node, "olpc,xo1-battery")) {
0281
0282
0283
0284
0285
0286 return;
0287 }
0288
0289
0290 olpc_dt_interpret("\" /pci/display@1,1\" find-device");
0291 olpc_dt_interpret(" new-device");
0292 olpc_dt_interpret(" \" dcon\" device-name");
0293 olpc_dt_interpret(" \" olpc,xo1-dcon\" +compatible");
0294 olpc_dt_interpret(" finish-device");
0295 olpc_dt_interpret("device-end");
0296
0297 olpc_dt_interpret("\" /rtc\" find-device");
0298 olpc_dt_interpret(" \" olpc,xo1-rtc\" +compatible");
0299 olpc_dt_interpret("device-end");
0300 }
0301
0302
0303 olpc_dt_interpret("\" /battery@0\" find-device");
0304 olpc_dt_interpret(" \" olpc,xo1-battery\" +compatible");
0305 olpc_dt_interpret("device-end");
0306 }
0307
0308 void __init olpc_dt_build_devicetree(void)
0309 {
0310 phandle root;
0311
0312 if (!olpc_ofw_is_installed())
0313 return;
0314
0315 olpc_dt_fixup();
0316
0317 root = olpc_dt_getsibling(0);
0318 if (!root) {
0319 pr_err("PROM: unable to get root node from OFW!\n");
0320 return;
0321 }
0322 of_pdt_build_devicetree(root, &prom_olpc_ops);
0323
0324 pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
0325 prom_early_allocated);
0326 }