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 | |
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>
-rw-r--r-- | arch/x86/Kconfig | 6 | ||||
-rw-r--r-- | arch/x86/include/asm/olpc_ofw.h | 9 | ||||
-rw-r--r-- | arch/x86/include/asm/prom.h | 1 | ||||
-rw-r--r-- | arch/x86/mm/init_32.c | 2 | ||||
-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 |
7 files changed, 189 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e330da21b84f..ef34031a8339 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -2049,11 +2049,17 @@ config OLPC_OPENFIRMWARE | |||
2049 | bool "Support for OLPC's Open Firmware" | 2049 | bool "Support for OLPC's Open Firmware" |
2050 | depends on !X86_64 && !X86_PAE | 2050 | depends on !X86_64 && !X86_PAE |
2051 | default n | 2051 | default n |
2052 | select OF | ||
2052 | help | 2053 | help |
2053 | This option adds support for the implementation of Open Firmware | 2054 | This option adds support for the implementation of Open Firmware |
2054 | that is used on the OLPC XO-1 Children's Machine. | 2055 | that is used on the OLPC XO-1 Children's Machine. |
2055 | If unsure, say N here. | 2056 | If unsure, say N here. |
2056 | 2057 | ||
2058 | config OLPC_OPENFIRMWARE_DT | ||
2059 | bool | ||
2060 | default y if OLPC_OPENFIRMWARE && PROC_DEVICETREE | ||
2061 | select OF_PROMTREE | ||
2062 | |||
2057 | endif # X86_32 | 2063 | endif # X86_32 |
2058 | 2064 | ||
2059 | config AMD_NB | 2065 | config AMD_NB |
diff --git a/arch/x86/include/asm/olpc_ofw.h b/arch/x86/include/asm/olpc_ofw.h index 2a8478140bb3..641988efe063 100644 --- a/arch/x86/include/asm/olpc_ofw.h +++ b/arch/x86/include/asm/olpc_ofw.h | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | #ifdef CONFIG_OLPC_OPENFIRMWARE | 9 | #ifdef CONFIG_OLPC_OPENFIRMWARE |
10 | 10 | ||
11 | extern bool olpc_ofw_is_installed(void); | ||
12 | |||
11 | /* run an OFW command by calling into the firmware */ | 13 | /* run an OFW command by calling into the firmware */ |
12 | #define olpc_ofw(name, args, res) \ | 14 | #define olpc_ofw(name, args, res) \ |
13 | __olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res) | 15 | __olpc_ofw((name), ARRAY_SIZE(args), args, ARRAY_SIZE(res), res) |
@@ -26,10 +28,17 @@ extern bool olpc_ofw_present(void); | |||
26 | 28 | ||
27 | #else /* !CONFIG_OLPC_OPENFIRMWARE */ | 29 | #else /* !CONFIG_OLPC_OPENFIRMWARE */ |
28 | 30 | ||
31 | static inline bool olpc_ofw_is_installed(void) { return false; } | ||
29 | static inline void olpc_ofw_detect(void) { } | 32 | static inline void olpc_ofw_detect(void) { } |
30 | static inline void setup_olpc_ofw_pgd(void) { } | 33 | static inline void setup_olpc_ofw_pgd(void) { } |
31 | static inline bool olpc_ofw_present(void) { return false; } | 34 | static inline bool olpc_ofw_present(void) { return false; } |
32 | 35 | ||
33 | #endif /* !CONFIG_OLPC_OPENFIRMWARE */ | 36 | #endif /* !CONFIG_OLPC_OPENFIRMWARE */ |
34 | 37 | ||
38 | #ifdef CONFIG_OLPC_OPENFIRMWARE_DT | ||
39 | extern void olpc_dt_build_devicetree(void); | ||
40 | #else | ||
41 | static inline void olpc_dt_build_devicetree(void) { } | ||
42 | #endif /* CONFIG_OLPC_OPENFIRMWARE_DT */ | ||
43 | |||
35 | #endif /* _ASM_X86_OLPC_OFW_H */ | 44 | #endif /* _ASM_X86_OLPC_OFW_H */ |
diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h new file mode 100644 index 000000000000..b4ec95f07518 --- /dev/null +++ b/arch/x86/include/asm/prom.h | |||
@@ -0,0 +1 @@ | |||
/* dummy prom.h; here to make linux/of.h's #includes happy */ | |||
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 0e969f9f401b..8c852e4af452 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/bugs.h> | 45 | #include <asm/bugs.h> |
46 | #include <asm/tlb.h> | 46 | #include <asm/tlb.h> |
47 | #include <asm/tlbflush.h> | 47 | #include <asm/tlbflush.h> |
48 | #include <asm/olpc_ofw.h> | ||
48 | #include <asm/pgalloc.h> | 49 | #include <asm/pgalloc.h> |
49 | #include <asm/sections.h> | 50 | #include <asm/sections.h> |
50 | #include <asm/paravirt.h> | 51 | #include <asm/paravirt.h> |
@@ -715,6 +716,7 @@ void __init paging_init(void) | |||
715 | /* | 716 | /* |
716 | * NOTE: at this point the bootmem allocator is fully available. | 717 | * NOTE: at this point the bootmem allocator is fully available. |
717 | */ | 718 | */ |
719 | olpc_dt_build_devicetree(); | ||
718 | sparse_init(); | 720 | sparse_init(); |
719 | zone_sizes_init(); | 721 | zone_sizes_init(); |
720 | } | 722 | } |
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 | } | ||