diff options
author | Andres Salomon <dilinger@queued.net> | 2010-11-17 01:09:52 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2010-12-15 20:11:30 -0500 |
commit | c10d1e260f7cb6766dc76b4e36ed8f4be53f195a (patch) | |
tree | bcbeb1e08d65cd24a4c471d0fe8345ada28a076e /arch/x86/platform | |
parent | 4722d194e648fb5755faecee895b96b26f9732f3 (diff) |
x86, olpc: Add OLPC device-tree support
Make use of PROC_DEVICETREE to export the tree, and sparc's PROMTREE code to
call into OLPC's Open Firmware to build the tree.
v5: fix buglet with root node check (introduced in v4)
v4: address some minor style issues pointed out by Grant, and explicitly cast
negative phandle checks to s32.
v3: rename olpc_prom to olpc_dt
- rework Kconfig entries
- drop devtree build hook from proc, instead adding a call to x86's
paging_init (similarly to how sparc64 does it)
- switch allocation from using slab to alloc_bootmem. this allows
the DT to be built earlier during boot (during setup_arch); the
downside is that there are some 1200 bootmem reservations that are
done during boot. Not ideal..
- add a helper olpc_ofw_is_installed function to test for the
existence and successful detection of OLPC's OFW.
Signed-off-by: Andres Salomon <dilinger@queued.net>
LKML-Reference: <20101116220952.26526a80@queued.net>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/platform')
-rw-r--r-- | arch/x86/platform/olpc/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/platform/olpc/olpc_dt.c | 165 | ||||
-rw-r--r-- | arch/x86/platform/olpc/olpc_ofw.c | 5 |
3 files changed, 171 insertions, 0 deletions
diff --git a/arch/x86/platform/olpc/Makefile b/arch/x86/platform/olpc/Makefile index c31b8fcb5a86..e797428b163b 100644 --- a/arch/x86/platform/olpc/Makefile +++ b/arch/x86/platform/olpc/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_OLPC) += olpc.o | 1 | obj-$(CONFIG_OLPC) += olpc.o |
2 | obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o | 2 | obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o |
3 | obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o | 3 | obj-$(CONFIG_OLPC_OPENFIRMWARE) += olpc_ofw.o |
4 | obj-$(CONFIG_OLPC_OPENFIRMWARE_DT) += olpc_dt.o | ||
diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c new file mode 100644 index 000000000000..70546975a920 --- /dev/null +++ b/arch/x86/platform/olpc/olpc_dt.c | |||
@@ -0,0 +1,165 @@ | |||
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 | void *res; | ||
130 | |||
131 | res = alloc_bootmem(size); | ||
132 | if (res) | ||
133 | memset(res, 0, size); | ||
134 | |||
135 | prom_early_allocated += size; | ||
136 | |||
137 | return res; | ||
138 | } | ||
139 | |||
140 | static struct of_pdt_ops prom_olpc_ops __initdata = { | ||
141 | .nextprop = olpc_dt_nextprop, | ||
142 | .getproplen = olpc_dt_getproplen, | ||
143 | .getproperty = olpc_dt_getproperty, | ||
144 | .getchild = olpc_dt_getchild, | ||
145 | .getsibling = olpc_dt_getsibling, | ||
146 | .pkg2path = olpc_dt_pkg2path, | ||
147 | }; | ||
148 | |||
149 | void __init olpc_dt_build_devicetree(void) | ||
150 | { | ||
151 | phandle root; | ||
152 | |||
153 | if (!olpc_ofw_is_installed()) | ||
154 | return; | ||
155 | |||
156 | root = olpc_dt_getsibling(0); | ||
157 | if (!root) { | ||
158 | pr_err("PROM: unable to get root node from OFW!\n"); | ||
159 | return; | ||
160 | } | ||
161 | of_pdt_build_devicetree(root, &prom_olpc_ops); | ||
162 | |||
163 | pr_info("PROM DT: Built device tree with %u bytes of memory.\n", | ||
164 | prom_early_allocated); | ||
165 | } | ||
diff --git a/arch/x86/platform/olpc/olpc_ofw.c b/arch/x86/platform/olpc/olpc_ofw.c index 787320464379..e7604f62870d 100644 --- a/arch/x86/platform/olpc/olpc_ofw.c +++ b/arch/x86/platform/olpc/olpc_ofw.c | |||
@@ -110,3 +110,8 @@ void __init olpc_ofw_detect(void) | |||
110 | (unsigned long)olpc_ofw_cif, (-start) >> 20); | 110 | (unsigned long)olpc_ofw_cif, (-start) >> 20); |
111 | reserve_top_address(-start); | 111 | reserve_top_address(-start); |
112 | } | 112 | } |
113 | |||
114 | bool __init olpc_ofw_is_installed(void) | ||
115 | { | ||
116 | return olpc_ofw_cif != NULL; | ||
117 | } | ||