aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform/olpc
diff options
context:
space:
mode:
authorDaniel Drake <dsd@laptop.org>2011-06-25 12:34:08 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2011-07-06 17:44:19 -0400
commitf70d8ef4745349000dc599b6873a8b866289c694 (patch)
treeb3fbc0a71671532e23533114e759e0519570f6ab /arch/x86/platform/olpc
parentfe0d42203cb5616eeff68b14576a0f7e2dd56625 (diff)
x86, olpc: Add missing elements to device tree
In response to new device tree code in the kernel, OLPC will start using it for probing of certain devices. However, some firmware fixes are needed to put the devicetree into a usable state. Retain compatibility with old firmware by fixing up the device tree at boot-time if it does not contain the new nodes/properties that we need for probing. This is the same approach taken on PPC platforms. Signed-off-by: Daniel Drake <dsd@laptop.org> Link: http://lkml.kernel.org/r/1309019658-1712-2-git-send-email-dsd@laptop.org Acked-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Andres Salomon <dilinger@queued.net> Cc: devicetree-discuss@lists.ozlabs.org Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/platform/olpc')
-rw-r--r--arch/x86/platform/olpc/olpc_dt.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c
index d39f63d017d2..d6ee92986920 100644
--- a/arch/x86/platform/olpc/olpc_dt.c
+++ b/arch/x86/platform/olpc/olpc_dt.c
@@ -165,6 +165,107 @@ static struct of_pdt_ops prom_olpc_ops __initdata = {
165 .pkg2path = olpc_dt_pkg2path, 165 .pkg2path = olpc_dt_pkg2path,
166}; 166};
167 167
168static phandle __init olpc_dt_finddevice(const char *path)
169{
170 phandle node;
171 const void *args[] = { path };
172 void *res[] = { &node };
173
174 if (olpc_ofw("finddevice", args, res)) {
175 pr_err("olpc_dt: finddevice failed!\n");
176 return 0;
177 }
178
179 if ((s32) node == -1)
180 return 0;
181
182 return node;
183}
184
185static int __init olpc_dt_interpret(const char *words)
186{
187 int result;
188 const void *args[] = { words };
189 void *res[] = { &result };
190
191 if (olpc_ofw("interpret", args, res)) {
192 pr_err("olpc_dt: interpret failed!\n");
193 return -1;
194 }
195
196 return result;
197}
198
199/*
200 * Extract board revision directly from OFW device tree.
201 * We can't use olpc_platform_info because that hasn't been set up yet.
202 */
203static u32 __init olpc_dt_get_board_revision(void)
204{
205 phandle node;
206 __be32 rev;
207 int r;
208
209 node = olpc_dt_finddevice("/");
210 if (!node)
211 return 0;
212
213 r = olpc_dt_getproperty(node, "board-revision-int",
214 (char *) &rev, sizeof(rev));
215 if (r < 0)
216 return 0;
217
218 return be32_to_cpu(rev);
219}
220
221void __init olpc_dt_fixup(void)
222{
223 int r;
224 char buf[64];
225 phandle node;
226 u32 board_rev;
227
228 node = olpc_dt_finddevice("/battery@0");
229 if (!node)
230 return;
231
232 /*
233 * If the battery node has a compatible property, we are running a new
234 * enough firmware and don't have fixups to make.
235 */
236 r = olpc_dt_getproperty(node, "compatible", buf, sizeof(buf));
237 if (r > 0)
238 return;
239
240 pr_info("PROM DT: Old firmware detected, applying fixes\n");
241
242 /* Add olpc,xo1-battery compatible marker to battery node */
243 olpc_dt_interpret("\" /battery@0\" find-device"
244 " \" olpc,xo1-battery\" +compatible"
245 " device-end");
246
247 board_rev = olpc_dt_get_board_revision();
248 if (!board_rev)
249 return;
250
251 if (board_rev >= olpc_board_pre(0xd0)) {
252 /* XO-1.5: add dcon device */
253 olpc_dt_interpret("\" /pci/display@1\" find-device"
254 " new-device"
255 " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible"
256 " finish-device device-end");
257 } else {
258 /* XO-1: add dcon device, mark RTC as olpc,xo1-rtc */
259 olpc_dt_interpret("\" /pci/display@1,1\" find-device"
260 " new-device"
261 " \" dcon\" device-name \" olpc,xo1-dcon\" +compatible"
262 " finish-device device-end"
263 " \" /rtc\" find-device"
264 " \" olpc,xo1-rtc\" +compatible"
265 " device-end");
266 }
267}
268
168void __init olpc_dt_build_devicetree(void) 269void __init olpc_dt_build_devicetree(void)
169{ 270{
170 phandle root; 271 phandle root;
@@ -172,6 +273,8 @@ void __init olpc_dt_build_devicetree(void)
172 if (!olpc_ofw_is_installed()) 273 if (!olpc_ofw_is_installed())
173 return; 274 return;
174 275
276 olpc_dt_fixup();
277
175 root = olpc_dt_getsibling(0); 278 root = olpc_dt_getsibling(0);
176 if (!root) { 279 if (!root) {
177 pr_err("PROM: unable to get root node from OFW!\n"); 280 pr_err("PROM: unable to get root node from OFW!\n");