diff options
Diffstat (limited to 'arch/x86/platform/olpc/olpc_dt.c')
-rw-r--r-- | arch/x86/platform/olpc/olpc_dt.c | 103 |
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 | ||
168 | static 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 | |||
185 | static 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 | */ | ||
203 | static 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 | |||
221 | void __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 | |||
168 | void __init olpc_dt_build_devicetree(void) | 269 | void __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"); |