diff options
author | Michal Simek <monstr@monstr.eu> | 2009-03-27 09:25:12 -0400 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-03-27 09:25:12 -0400 |
commit | 12e8414263f47352b3fec8ba5efff160584202e0 (patch) | |
tree | 76dffeeda1d792dafb1fc056a3a88e3fe1b9696a /arch/microblaze | |
parent | 406107dacde125346c313d34534eed937eb25444 (diff) |
microblaze_v8: Open firmware files
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Reviewed-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: John Linn <john.linn@xilinx.com>
Acked-by: John Williams <john.williams@petalogix.com>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch/microblaze')
-rw-r--r-- | arch/microblaze/include/asm/of_device.h | 45 | ||||
-rw-r--r-- | arch/microblaze/include/asm/of_platform.h | 64 | ||||
-rw-r--r-- | arch/microblaze/include/asm/prom.h | 313 | ||||
-rw-r--r-- | arch/microblaze/kernel/of_device.c | 115 | ||||
-rw-r--r-- | arch/microblaze/kernel/of_platform.c | 201 | ||||
-rw-r--r-- | arch/microblaze/kernel/prom.c | 1147 | ||||
-rw-r--r-- | arch/microblaze/kernel/prom_parse.c | 1025 |
7 files changed, 2910 insertions, 0 deletions
diff --git a/arch/microblaze/include/asm/of_device.h b/arch/microblaze/include/asm/of_device.h new file mode 100644 index 000000000000..ba917cfaefe6 --- /dev/null +++ b/arch/microblaze/include/asm/of_device.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu> | ||
3 | * | ||
4 | * based on PowerPC of_device.h | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #ifndef _ASM_MICROBLAZE_OF_DEVICE_H | ||
12 | #define _ASM_MICROBLAZE_OF_DEVICE_H | ||
13 | #ifdef __KERNEL__ | ||
14 | |||
15 | #include <linux/device.h> | ||
16 | #include <linux/of.h> | ||
17 | |||
18 | /* | ||
19 | * The of_device is a kind of "base class" that is a superset of | ||
20 | * struct device for use by devices attached to an OF node and | ||
21 | * probed using OF properties. | ||
22 | */ | ||
23 | struct of_device { | ||
24 | struct device_node *node; /* to be obsoleted */ | ||
25 | u64 dma_mask; /* DMA mask */ | ||
26 | struct device dev; /* Generic device interface */ | ||
27 | }; | ||
28 | |||
29 | extern ssize_t of_device_get_modalias(struct of_device *ofdev, | ||
30 | char *str, ssize_t len); | ||
31 | |||
32 | extern struct of_device *of_device_alloc(struct device_node *np, | ||
33 | const char *bus_id, | ||
34 | struct device *parent); | ||
35 | |||
36 | extern int of_device_uevent(struct device *dev, | ||
37 | struct kobj_uevent_env *env); | ||
38 | |||
39 | extern void of_device_make_bus_id(struct of_device *dev); | ||
40 | |||
41 | /* This is just here during the transition */ | ||
42 | #include <linux/of_device.h> | ||
43 | |||
44 | #endif /* __KERNEL__ */ | ||
45 | #endif /* _ASM_MICROBLAZE_OF_DEVICE_H */ | ||
diff --git a/arch/microblaze/include/asm/of_platform.h b/arch/microblaze/include/asm/of_platform.h new file mode 100644 index 000000000000..187c0eedaece --- /dev/null +++ b/arch/microblaze/include/asm/of_platform.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. | ||
3 | * <benh@kernel.crashing.org> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #ifndef _ASM_MICROBLAZE_OF_PLATFORM_H | ||
12 | #define _ASM_MICROBLAZE_OF_PLATFORM_H | ||
13 | |||
14 | /* This is just here during the transition */ | ||
15 | #include <linux/of_platform.h> | ||
16 | |||
17 | /* | ||
18 | * The list of OF IDs below is used for matching bus types in the | ||
19 | * system whose devices are to be exposed as of_platform_devices. | ||
20 | * | ||
21 | * This is the default list valid for most platforms. This file provides | ||
22 | * functions who can take an explicit list if necessary though | ||
23 | * | ||
24 | * The search is always performed recursively looking for children of | ||
25 | * the provided device_node and recursively if such a children matches | ||
26 | * a bus type in the list | ||
27 | */ | ||
28 | |||
29 | static const struct of_device_id of_default_bus_ids[] = { | ||
30 | { .type = "soc", }, | ||
31 | { .compatible = "soc", }, | ||
32 | { .type = "plb5", }, | ||
33 | { .type = "plb4", }, | ||
34 | { .type = "opb", }, | ||
35 | { .type = "simple", }, | ||
36 | {}, | ||
37 | }; | ||
38 | |||
39 | /* Platform drivers register/unregister */ | ||
40 | static inline int of_register_platform_driver(struct of_platform_driver *drv) | ||
41 | { | ||
42 | return of_register_driver(drv, &of_platform_bus_type); | ||
43 | } | ||
44 | static inline void of_unregister_platform_driver(struct of_platform_driver *drv) | ||
45 | { | ||
46 | of_unregister_driver(drv); | ||
47 | } | ||
48 | |||
49 | /* Platform devices and busses creation */ | ||
50 | extern struct of_device *of_platform_device_create(struct device_node *np, | ||
51 | const char *bus_id, | ||
52 | struct device *parent); | ||
53 | /* pseudo "matches" value to not do deep probe */ | ||
54 | #define OF_NO_DEEP_PROBE ((struct of_device_id *)-1) | ||
55 | |||
56 | extern int of_platform_bus_probe(struct device_node *root, | ||
57 | const struct of_device_id *matches, | ||
58 | struct device *parent); | ||
59 | |||
60 | extern struct of_device *of_find_device_by_phandle(phandle ph); | ||
61 | |||
62 | extern void of_instantiate_rtc(void); | ||
63 | |||
64 | #endif /* _ASM_MICROBLAZE_OF_PLATFORM_H */ | ||
diff --git a/arch/microblaze/include/asm/prom.h b/arch/microblaze/include/asm/prom.h new file mode 100644 index 000000000000..20f7b3a926e8 --- /dev/null +++ b/arch/microblaze/include/asm/prom.h | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * Definitions for talking to the Open Firmware PROM on | ||
3 | * Power Macintosh computers. | ||
4 | * | ||
5 | * Copyright (C) 1996-2005 Paul Mackerras. | ||
6 | * | ||
7 | * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #ifndef _ASM_MICROBLAZE_PROM_H | ||
16 | #define _ASM_MICROBLAZE_PROM_H | ||
17 | #ifdef __KERNEL__ | ||
18 | |||
19 | #include <linux/types.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/atomic.h> | ||
24 | |||
25 | #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 | ||
26 | #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 | ||
27 | |||
28 | #define of_compat_cmp(s1, s2, l) strncasecmp((s1), (s2), (l)) | ||
29 | #define of_prop_cmp(s1, s2) strcmp((s1), (s2)) | ||
30 | #define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) | ||
31 | |||
32 | /* Definitions used by the flattened device tree */ | ||
33 | #define OF_DT_HEADER 0xd00dfeed /* marker */ | ||
34 | #define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ | ||
35 | #define OF_DT_END_NODE 0x2 /* End node */ | ||
36 | #define OF_DT_PROP 0x3 /* Property: name off, size, content */ | ||
37 | #define OF_DT_NOP 0x4 /* nop */ | ||
38 | #define OF_DT_END 0x9 | ||
39 | |||
40 | #define OF_DT_VERSION 0x10 | ||
41 | |||
42 | /* | ||
43 | * This is what gets passed to the kernel by prom_init or kexec | ||
44 | * | ||
45 | * The dt struct contains the device tree structure, full pathes and | ||
46 | * property contents. The dt strings contain a separate block with just | ||
47 | * the strings for the property names, and is fully page aligned and | ||
48 | * self contained in a page, so that it can be kept around by the kernel, | ||
49 | * each property name appears only once in this page (cheap compression) | ||
50 | * | ||
51 | * the mem_rsvmap contains a map of reserved ranges of physical memory, | ||
52 | * passing it here instead of in the device-tree itself greatly simplifies | ||
53 | * the job of everybody. It's just a list of u64 pairs (base/size) that | ||
54 | * ends when size is 0 | ||
55 | */ | ||
56 | struct boot_param_header { | ||
57 | u32 magic; /* magic word OF_DT_HEADER */ | ||
58 | u32 totalsize; /* total size of DT block */ | ||
59 | u32 off_dt_struct; /* offset to structure */ | ||
60 | u32 off_dt_strings; /* offset to strings */ | ||
61 | u32 off_mem_rsvmap; /* offset to memory reserve map */ | ||
62 | u32 version; /* format version */ | ||
63 | u32 last_comp_version; /* last compatible version */ | ||
64 | /* version 2 fields below */ | ||
65 | u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ | ||
66 | /* version 3 fields below */ | ||
67 | u32 dt_strings_size; /* size of the DT strings block */ | ||
68 | /* version 17 fields below */ | ||
69 | u32 dt_struct_size; /* size of the DT structure block */ | ||
70 | }; | ||
71 | |||
72 | typedef u32 phandle; | ||
73 | typedef u32 ihandle; | ||
74 | |||
75 | struct property { | ||
76 | char *name; | ||
77 | int length; | ||
78 | void *value; | ||
79 | struct property *next; | ||
80 | }; | ||
81 | |||
82 | struct device_node { | ||
83 | const char *name; | ||
84 | const char *type; | ||
85 | phandle node; | ||
86 | phandle linux_phandle; | ||
87 | char *full_name; | ||
88 | |||
89 | struct property *properties; | ||
90 | struct property *deadprops; /* removed properties */ | ||
91 | struct device_node *parent; | ||
92 | struct device_node *child; | ||
93 | struct device_node *sibling; | ||
94 | struct device_node *next; /* next device of same type */ | ||
95 | struct device_node *allnext; /* next in list of all nodes */ | ||
96 | struct proc_dir_entry *pde; /* this node's proc directory */ | ||
97 | struct kref kref; | ||
98 | unsigned long _flags; | ||
99 | void *data; | ||
100 | }; | ||
101 | |||
102 | extern struct device_node *of_chosen; | ||
103 | |||
104 | static inline int of_node_check_flag(struct device_node *n, unsigned long flag) | ||
105 | { | ||
106 | return test_bit(flag, &n->_flags); | ||
107 | } | ||
108 | |||
109 | static inline void of_node_set_flag(struct device_node *n, unsigned long flag) | ||
110 | { | ||
111 | set_bit(flag, &n->_flags); | ||
112 | } | ||
113 | |||
114 | #define HAVE_ARCH_DEVTREE_FIXUPS | ||
115 | |||
116 | static inline void set_node_proc_entry(struct device_node *dn, | ||
117 | struct proc_dir_entry *de) | ||
118 | { | ||
119 | dn->pde = de; | ||
120 | } | ||
121 | |||
122 | extern struct device_node *allnodes; /* temporary while merging */ | ||
123 | extern rwlock_t devtree_lock; /* temporary while merging */ | ||
124 | |||
125 | extern struct device_node *of_find_all_nodes(struct device_node *prev); | ||
126 | extern struct device_node *of_node_get(struct device_node *node); | ||
127 | extern void of_node_put(struct device_node *node); | ||
128 | |||
129 | /* For scanning the flat device-tree at boot time */ | ||
130 | extern int __init of_scan_flat_dt(int (*it)(unsigned long node, | ||
131 | const char *uname, int depth, | ||
132 | void *data), | ||
133 | void *data); | ||
134 | extern void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | ||
135 | unsigned long *size); | ||
136 | extern int __init | ||
137 | of_flat_dt_is_compatible(unsigned long node, const char *name); | ||
138 | extern unsigned long __init of_get_flat_dt_root(void); | ||
139 | |||
140 | /* For updating the device tree at runtime */ | ||
141 | extern void of_attach_node(struct device_node *); | ||
142 | extern void of_detach_node(struct device_node *); | ||
143 | |||
144 | /* Other Prototypes */ | ||
145 | extern void finish_device_tree(void); | ||
146 | extern void unflatten_device_tree(void); | ||
147 | extern int early_uartlite_console(void); | ||
148 | extern void early_init_devtree(void *); | ||
149 | extern int machine_is_compatible(const char *compat); | ||
150 | extern void print_properties(struct device_node *node); | ||
151 | extern int prom_n_intr_cells(struct device_node *np); | ||
152 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | ||
153 | extern int prom_add_property(struct device_node *np, struct property *prop); | ||
154 | extern int prom_remove_property(struct device_node *np, struct property *prop); | ||
155 | extern int prom_update_property(struct device_node *np, | ||
156 | struct property *newprop, | ||
157 | struct property *oldprop); | ||
158 | |||
159 | extern struct resource *request_OF_resource(struct device_node *node, | ||
160 | int index, const char *name_postfix); | ||
161 | extern int release_OF_resource(struct device_node *node, int index); | ||
162 | |||
163 | /* | ||
164 | * OF address retreival & translation | ||
165 | */ | ||
166 | |||
167 | /* Helper to read a big number; size is in cells (not bytes) */ | ||
168 | static inline u64 of_read_number(const u32 *cell, int size) | ||
169 | { | ||
170 | u64 r = 0; | ||
171 | while (size--) | ||
172 | r = (r << 32) | *(cell++); | ||
173 | return r; | ||
174 | } | ||
175 | |||
176 | /* Like of_read_number, but we want an unsigned long result */ | ||
177 | #define of_read_ulong(cell, size) of_read_number(cell, size) | ||
178 | |||
179 | /* Translate an OF address block into a CPU physical address | ||
180 | */ | ||
181 | extern u64 of_translate_address(struct device_node *np, const u32 *addr); | ||
182 | |||
183 | /* Extract an address from a device, returns the region size and | ||
184 | * the address space flags too. The PCI version uses a BAR number | ||
185 | * instead of an absolute index | ||
186 | */ | ||
187 | extern const u32 *of_get_address(struct device_node *dev, int index, | ||
188 | u64 *size, unsigned int *flags); | ||
189 | extern const u32 *of_get_pci_address(struct device_node *dev, int bar_no, | ||
190 | u64 *size, unsigned int *flags); | ||
191 | |||
192 | /* Get an address as a resource. Note that if your address is | ||
193 | * a PIO address, the conversion will fail if the physical address | ||
194 | * can't be internally converted to an IO token with | ||
195 | * pci_address_to_pio(), that is because it's either called to early | ||
196 | * or it can't be matched to any host bridge IO space | ||
197 | */ | ||
198 | extern int of_address_to_resource(struct device_node *dev, int index, | ||
199 | struct resource *r); | ||
200 | extern int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
201 | struct resource *r); | ||
202 | |||
203 | /* Parse the ibm,dma-window property of an OF node into the busno, phys and | ||
204 | * size parameters. | ||
205 | */ | ||
206 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, | ||
207 | unsigned long *busno, unsigned long *phys, unsigned long *size); | ||
208 | |||
209 | extern void kdump_move_device_tree(void); | ||
210 | |||
211 | /* CPU OF node matching */ | ||
212 | struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); | ||
213 | |||
214 | /* Get the MAC address */ | ||
215 | extern const void *of_get_mac_address(struct device_node *np); | ||
216 | |||
217 | /* | ||
218 | * OF interrupt mapping | ||
219 | */ | ||
220 | |||
221 | /* This structure is returned when an interrupt is mapped. The controller | ||
222 | * field needs to be put() after use | ||
223 | */ | ||
224 | |||
225 | #define OF_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ | ||
226 | |||
227 | struct of_irq { | ||
228 | struct device_node *controller; /* Interrupt controller node */ | ||
229 | u32 size; /* Specifier size */ | ||
230 | u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ | ||
231 | }; | ||
232 | |||
233 | /** | ||
234 | * of_irq_map_init - Initialize the irq remapper | ||
235 | * @flags: flags defining workarounds to enable | ||
236 | * | ||
237 | * Some machines have bugs in the device-tree which require certain workarounds | ||
238 | * to be applied. Call this before any interrupt mapping attempts to enable | ||
239 | * those workarounds. | ||
240 | */ | ||
241 | #define OF_IMAP_OLDWORLD_MAC 0x00000001 | ||
242 | #define OF_IMAP_NO_PHANDLE 0x00000002 | ||
243 | |||
244 | extern void of_irq_map_init(unsigned int flags); | ||
245 | |||
246 | /** | ||
247 | * of_irq_map_raw - Low level interrupt tree parsing | ||
248 | * @parent: the device interrupt parent | ||
249 | * @intspec: interrupt specifier ("interrupts" property of the device) | ||
250 | * @ointsize: size of the passed in interrupt specifier | ||
251 | * @addr: address specifier (start of "reg" property of the device) | ||
252 | * @out_irq: structure of_irq filled by this function | ||
253 | * | ||
254 | * Returns 0 on success and a negative number on error | ||
255 | * | ||
256 | * This function is a low-level interrupt tree walking function. It | ||
257 | * can be used to do a partial walk with synthetized reg and interrupts | ||
258 | * properties, for example when resolving PCI interrupts when no device | ||
259 | * node exist for the parent. | ||
260 | * | ||
261 | */ | ||
262 | |||
263 | extern int of_irq_map_raw(struct device_node *parent, const u32 *intspec, | ||
264 | u32 ointsize, const u32 *addr, | ||
265 | struct of_irq *out_irq); | ||
266 | |||
267 | /** | ||
268 | * of_irq_map_one - Resolve an interrupt for a device | ||
269 | * @device: the device whose interrupt is to be resolved | ||
270 | * @index: index of the interrupt to resolve | ||
271 | * @out_irq: structure of_irq filled by this function | ||
272 | * | ||
273 | * This function resolves an interrupt, walking the tree, for a given | ||
274 | * device-tree node. It's the high level pendant to of_irq_map_raw(). | ||
275 | * It also implements the workarounds for OldWolrd Macs. | ||
276 | */ | ||
277 | extern int of_irq_map_one(struct device_node *device, int index, | ||
278 | struct of_irq *out_irq); | ||
279 | |||
280 | /** | ||
281 | * of_irq_map_pci - Resolve the interrupt for a PCI device | ||
282 | * @pdev: the device whose interrupt is to be resolved | ||
283 | * @out_irq: structure of_irq filled by this function | ||
284 | * | ||
285 | * This function resolves the PCI interrupt for a given PCI device. If a | ||
286 | * device-node exists for a given pci_dev, it will use normal OF tree | ||
287 | * walking. If not, it will implement standard swizzling and walk up the | ||
288 | * PCI tree until an device-node is found, at which point it will finish | ||
289 | * resolving using the OF tree walking. | ||
290 | */ | ||
291 | struct pci_dev; | ||
292 | extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq); | ||
293 | |||
294 | extern int of_irq_to_resource(struct device_node *dev, int index, | ||
295 | struct resource *r); | ||
296 | |||
297 | /** | ||
298 | * of_iomap - Maps the memory mapped IO for a given device_node | ||
299 | * @device: the device whose io range will be mapped | ||
300 | * @index: index of the io range | ||
301 | * | ||
302 | * Returns a pointer to the mapped memory | ||
303 | */ | ||
304 | extern void __iomem *of_iomap(struct device_node *device, int index); | ||
305 | |||
306 | /* | ||
307 | * NB: This is here while we transition from using asm/prom.h | ||
308 | * to linux/of.h | ||
309 | */ | ||
310 | #include <linux/of.h> | ||
311 | |||
312 | #endif /* __KERNEL__ */ | ||
313 | #endif /* _ASM_MICROBLAZE_PROM_H */ | ||
diff --git a/arch/microblaze/kernel/of_device.c b/arch/microblaze/kernel/of_device.c new file mode 100644 index 000000000000..717edf4ad0b4 --- /dev/null +++ b/arch/microblaze/kernel/of_device.c | |||
@@ -0,0 +1,115 @@ | |||
1 | #include <linux/string.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/of.h> | ||
4 | #include <linux/init.h> | ||
5 | #include <linux/module.h> | ||
6 | #include <linux/mod_devicetable.h> | ||
7 | #include <linux/slab.h> | ||
8 | #include <linux/of_device.h> | ||
9 | |||
10 | #include <linux/errno.h> | ||
11 | |||
12 | void of_device_make_bus_id(struct of_device *dev) | ||
13 | { | ||
14 | static atomic_t bus_no_reg_magic; | ||
15 | struct device_node *node = dev->node; | ||
16 | char *name = dev->dev.bus_id; | ||
17 | const u32 *reg; | ||
18 | u64 addr; | ||
19 | int magic; | ||
20 | |||
21 | /* | ||
22 | * For MMIO, get the physical address | ||
23 | */ | ||
24 | reg = of_get_property(node, "reg", NULL); | ||
25 | if (reg) { | ||
26 | addr = of_translate_address(node, reg); | ||
27 | if (addr != OF_BAD_ADDR) { | ||
28 | snprintf(name, BUS_ID_SIZE, | ||
29 | "%llx.%s", (unsigned long long)addr, | ||
30 | node->name); | ||
31 | return; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | /* | ||
36 | * No BusID, use the node name and add a globally incremented | ||
37 | * counter (and pray...) | ||
38 | */ | ||
39 | magic = atomic_add_return(1, &bus_no_reg_magic); | ||
40 | snprintf(name, BUS_ID_SIZE, "%s.%d", node->name, magic - 1); | ||
41 | } | ||
42 | EXPORT_SYMBOL(of_device_make_bus_id); | ||
43 | |||
44 | struct of_device *of_device_alloc(struct device_node *np, | ||
45 | const char *bus_id, | ||
46 | struct device *parent) | ||
47 | { | ||
48 | struct of_device *dev; | ||
49 | |||
50 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
51 | if (!dev) | ||
52 | return NULL; | ||
53 | |||
54 | dev->node = of_node_get(np); | ||
55 | dev->dev.dma_mask = &dev->dma_mask; | ||
56 | dev->dev.parent = parent; | ||
57 | dev->dev.release = of_release_dev; | ||
58 | dev->dev.archdata.of_node = np; | ||
59 | |||
60 | if (bus_id) | ||
61 | strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); | ||
62 | else | ||
63 | of_device_make_bus_id(dev); | ||
64 | |||
65 | return dev; | ||
66 | } | ||
67 | EXPORT_SYMBOL(of_device_alloc); | ||
68 | |||
69 | int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
70 | { | ||
71 | struct of_device *ofdev; | ||
72 | const char *compat; | ||
73 | int seen = 0, cplen, sl; | ||
74 | |||
75 | if (!dev) | ||
76 | return -ENODEV; | ||
77 | |||
78 | ofdev = to_of_device(dev); | ||
79 | |||
80 | if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name)) | ||
81 | return -ENOMEM; | ||
82 | |||
83 | if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type)) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | /* Since the compatible field can contain pretty much anything | ||
87 | * it's not really legal to split it out with commas. We split it | ||
88 | * up using a number of environment variables instead. */ | ||
89 | |||
90 | compat = of_get_property(ofdev->node, "compatible", &cplen); | ||
91 | while (compat && *compat && cplen > 0) { | ||
92 | if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) | ||
93 | return -ENOMEM; | ||
94 | |||
95 | sl = strlen(compat) + 1; | ||
96 | compat += sl; | ||
97 | cplen -= sl; | ||
98 | seen++; | ||
99 | } | ||
100 | |||
101 | if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) | ||
102 | return -ENOMEM; | ||
103 | |||
104 | /* modalias is trickier, we add it in 2 steps */ | ||
105 | if (add_uevent_var(env, "MODALIAS=")) | ||
106 | return -ENOMEM; | ||
107 | sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1], | ||
108 | sizeof(env->buf) - env->buflen); | ||
109 | if (sl >= (sizeof(env->buf) - env->buflen)) | ||
110 | return -ENOMEM; | ||
111 | env->buflen += sl; | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | EXPORT_SYMBOL(of_device_uevent); | ||
diff --git a/arch/microblaze/kernel/of_platform.c b/arch/microblaze/kernel/of_platform.c new file mode 100644 index 000000000000..acf4574d0f18 --- /dev/null +++ b/arch/microblaze/kernel/of_platform.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. | ||
3 | * <benh@kernel.crashing.org> | ||
4 | * and Arnd Bergmann, IBM Corp. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #undef DEBUG | ||
14 | |||
15 | #include <linux/string.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mod_devicetable.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | |||
26 | #include <linux/errno.h> | ||
27 | #include <linux/topology.h> | ||
28 | #include <asm/atomic.h> | ||
29 | |||
30 | struct bus_type of_platform_bus_type = { | ||
31 | .uevent = of_device_uevent, | ||
32 | }; | ||
33 | EXPORT_SYMBOL(of_platform_bus_type); | ||
34 | |||
35 | static int __init of_bus_driver_init(void) | ||
36 | { | ||
37 | return of_bus_type_init(&of_platform_bus_type, "of_platform"); | ||
38 | } | ||
39 | postcore_initcall(of_bus_driver_init); | ||
40 | |||
41 | struct of_device *of_platform_device_create(struct device_node *np, | ||
42 | const char *bus_id, | ||
43 | struct device *parent) | ||
44 | { | ||
45 | struct of_device *dev; | ||
46 | |||
47 | dev = of_device_alloc(np, bus_id, parent); | ||
48 | if (!dev) | ||
49 | return NULL; | ||
50 | |||
51 | dev->dma_mask = 0xffffffffUL; | ||
52 | dev->dev.bus = &of_platform_bus_type; | ||
53 | |||
54 | /* We do not fill the DMA ops for platform devices by default. | ||
55 | * This is currently the responsibility of the platform code | ||
56 | * to do such, possibly using a device notifier | ||
57 | */ | ||
58 | |||
59 | if (of_device_register(dev) != 0) { | ||
60 | of_device_free(dev); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | return dev; | ||
65 | } | ||
66 | EXPORT_SYMBOL(of_platform_device_create); | ||
67 | |||
68 | /** | ||
69 | * of_platform_bus_create - Create an OF device for a bus node and all its | ||
70 | * children. Optionally recursively instanciate matching busses. | ||
71 | * @bus: device node of the bus to instanciate | ||
72 | * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to | ||
73 | * disallow recursive creation of child busses | ||
74 | */ | ||
75 | static int of_platform_bus_create(const struct device_node *bus, | ||
76 | const struct of_device_id *matches, | ||
77 | struct device *parent) | ||
78 | { | ||
79 | struct device_node *child; | ||
80 | struct of_device *dev; | ||
81 | int rc = 0; | ||
82 | |||
83 | for_each_child_of_node(bus, child) { | ||
84 | pr_debug(" create child: %s\n", child->full_name); | ||
85 | dev = of_platform_device_create(child, NULL, parent); | ||
86 | if (dev == NULL) | ||
87 | rc = -ENOMEM; | ||
88 | else if (!of_match_node(matches, child)) | ||
89 | continue; | ||
90 | if (rc == 0) { | ||
91 | pr_debug(" and sub busses\n"); | ||
92 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
93 | } | ||
94 | if (rc) { | ||
95 | of_node_put(child); | ||
96 | break; | ||
97 | } | ||
98 | } | ||
99 | return rc; | ||
100 | } | ||
101 | |||
102 | |||
103 | /** | ||
104 | * of_platform_bus_probe - Probe the device-tree for platform busses | ||
105 | * @root: parent of the first level to probe or NULL for the root of the tree | ||
106 | * @matches: match table, NULL to use the default | ||
107 | * @parent: parent to hook devices from, NULL for toplevel | ||
108 | * | ||
109 | * Note that children of the provided root are not instanciated as devices | ||
110 | * unless the specified root itself matches the bus list and is not NULL. | ||
111 | */ | ||
112 | |||
113 | int of_platform_bus_probe(struct device_node *root, | ||
114 | const struct of_device_id *matches, | ||
115 | struct device *parent) | ||
116 | { | ||
117 | struct device_node *child; | ||
118 | struct of_device *dev; | ||
119 | int rc = 0; | ||
120 | |||
121 | if (matches == NULL) | ||
122 | matches = of_default_bus_ids; | ||
123 | if (matches == OF_NO_DEEP_PROBE) | ||
124 | return -EINVAL; | ||
125 | if (root == NULL) | ||
126 | root = of_find_node_by_path("/"); | ||
127 | else | ||
128 | of_node_get(root); | ||
129 | |||
130 | pr_debug("of_platform_bus_probe()\n"); | ||
131 | pr_debug(" starting at: %s\n", root->full_name); | ||
132 | |||
133 | /* Do a self check of bus type, if there's a match, create | ||
134 | * children | ||
135 | */ | ||
136 | if (of_match_node(matches, root)) { | ||
137 | pr_debug(" root match, create all sub devices\n"); | ||
138 | dev = of_platform_device_create(root, NULL, parent); | ||
139 | if (dev == NULL) { | ||
140 | rc = -ENOMEM; | ||
141 | goto bail; | ||
142 | } | ||
143 | pr_debug(" create all sub busses\n"); | ||
144 | rc = of_platform_bus_create(root, matches, &dev->dev); | ||
145 | goto bail; | ||
146 | } | ||
147 | for_each_child_of_node(root, child) { | ||
148 | if (!of_match_node(matches, child)) | ||
149 | continue; | ||
150 | |||
151 | pr_debug(" match: %s\n", child->full_name); | ||
152 | dev = of_platform_device_create(child, NULL, parent); | ||
153 | if (dev == NULL) | ||
154 | rc = -ENOMEM; | ||
155 | else | ||
156 | rc = of_platform_bus_create(child, matches, &dev->dev); | ||
157 | if (rc) { | ||
158 | of_node_put(child); | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | bail: | ||
163 | of_node_put(root); | ||
164 | return rc; | ||
165 | } | ||
166 | EXPORT_SYMBOL(of_platform_bus_probe); | ||
167 | |||
168 | static int of_dev_node_match(struct device *dev, void *data) | ||
169 | { | ||
170 | return to_of_device(dev)->node == data; | ||
171 | } | ||
172 | |||
173 | struct of_device *of_find_device_by_node(struct device_node *np) | ||
174 | { | ||
175 | struct device *dev; | ||
176 | |||
177 | dev = bus_find_device(&of_platform_bus_type, | ||
178 | NULL, np, of_dev_node_match); | ||
179 | if (dev) | ||
180 | return to_of_device(dev); | ||
181 | return NULL; | ||
182 | } | ||
183 | EXPORT_SYMBOL(of_find_device_by_node); | ||
184 | |||
185 | static int of_dev_phandle_match(struct device *dev, void *data) | ||
186 | { | ||
187 | phandle *ph = data; | ||
188 | return to_of_device(dev)->node->linux_phandle == *ph; | ||
189 | } | ||
190 | |||
191 | struct of_device *of_find_device_by_phandle(phandle ph) | ||
192 | { | ||
193 | struct device *dev; | ||
194 | |||
195 | dev = bus_find_device(&of_platform_bus_type, | ||
196 | NULL, &ph, of_dev_phandle_match); | ||
197 | if (dev) | ||
198 | return to_of_device(dev); | ||
199 | return NULL; | ||
200 | } | ||
201 | EXPORT_SYMBOL(of_find_device_by_phandle); | ||
diff --git a/arch/microblaze/kernel/prom.c b/arch/microblaze/kernel/prom.c new file mode 100644 index 000000000000..475b1fac5cfd --- /dev/null +++ b/arch/microblaze/kernel/prom.c | |||
@@ -0,0 +1,1147 @@ | |||
1 | /* | ||
2 | * Procedures for creating, accessing and interpreting the device tree. | ||
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 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <stdarg.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/threads.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/stringify.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/initrd.h> | ||
27 | #include <linux/bitops.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kexec.h> | ||
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/irq.h> | ||
32 | #include <linux/lmb.h> | ||
33 | |||
34 | #include <asm/prom.h> | ||
35 | #include <asm/page.h> | ||
36 | #include <asm/processor.h> | ||
37 | #include <asm/irq.h> | ||
38 | #include <linux/io.h> | ||
39 | #include <asm/system.h> | ||
40 | #include <asm/mmu.h> | ||
41 | #include <asm/pgtable.h> | ||
42 | #include <linux/pci.h> | ||
43 | #include <asm/sections.h> | ||
44 | #include <asm/pci-bridge.h> | ||
45 | |||
46 | static int __initdata dt_root_addr_cells; | ||
47 | static int __initdata dt_root_size_cells; | ||
48 | |||
49 | typedef u32 cell_t; | ||
50 | |||
51 | static struct boot_param_header *initial_boot_params; | ||
52 | |||
53 | /* export that to outside world */ | ||
54 | struct device_node *of_chosen; | ||
55 | |||
56 | static inline char *find_flat_dt_string(u32 offset) | ||
57 | { | ||
58 | return ((char *)initial_boot_params) + | ||
59 | initial_boot_params->off_dt_strings + offset; | ||
60 | } | ||
61 | |||
62 | /** | ||
63 | * This function is used to scan the flattened device-tree, it is | ||
64 | * used to extract the memory informations at boot before we can | ||
65 | * unflatten the tree | ||
66 | */ | ||
67 | int __init of_scan_flat_dt(int (*it)(unsigned long node, | ||
68 | const char *uname, int depth, | ||
69 | void *data), | ||
70 | void *data) | ||
71 | { | ||
72 | unsigned long p = ((unsigned long)initial_boot_params) + | ||
73 | initial_boot_params->off_dt_struct; | ||
74 | int rc = 0; | ||
75 | int depth = -1; | ||
76 | |||
77 | do { | ||
78 | u32 tag = *((u32 *)p); | ||
79 | char *pathp; | ||
80 | |||
81 | p += 4; | ||
82 | if (tag == OF_DT_END_NODE) { | ||
83 | depth--; | ||
84 | continue; | ||
85 | } | ||
86 | if (tag == OF_DT_NOP) | ||
87 | continue; | ||
88 | if (tag == OF_DT_END) | ||
89 | break; | ||
90 | if (tag == OF_DT_PROP) { | ||
91 | u32 sz = *((u32 *)p); | ||
92 | p += 8; | ||
93 | if (initial_boot_params->version < 0x10) | ||
94 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | ||
95 | p += sz; | ||
96 | p = _ALIGN(p, 4); | ||
97 | continue; | ||
98 | } | ||
99 | if (tag != OF_DT_BEGIN_NODE) { | ||
100 | printk(KERN_WARNING "Invalid tag %x scanning flattened" | ||
101 | " device tree !\n", tag); | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | depth++; | ||
105 | pathp = (char *)p; | ||
106 | p = _ALIGN(p + strlen(pathp) + 1, 4); | ||
107 | if ((*pathp) == '/') { | ||
108 | char *lp, *np; | ||
109 | for (lp = NULL, np = pathp; *np; np++) | ||
110 | if ((*np) == '/') | ||
111 | lp = np+1; | ||
112 | if (lp != NULL) | ||
113 | pathp = lp; | ||
114 | } | ||
115 | rc = it(p, pathp, depth, data); | ||
116 | if (rc != 0) | ||
117 | break; | ||
118 | } while (1); | ||
119 | |||
120 | return rc; | ||
121 | } | ||
122 | |||
123 | unsigned long __init of_get_flat_dt_root(void) | ||
124 | { | ||
125 | unsigned long p = ((unsigned long)initial_boot_params) + | ||
126 | initial_boot_params->off_dt_struct; | ||
127 | |||
128 | while (*((u32 *)p) == OF_DT_NOP) | ||
129 | p += 4; | ||
130 | BUG_ON(*((u32 *)p) != OF_DT_BEGIN_NODE); | ||
131 | p += 4; | ||
132 | return _ALIGN(p + strlen((char *)p) + 1, 4); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * This function can be used within scan_flattened_dt callback to get | ||
137 | * access to properties | ||
138 | */ | ||
139 | void *__init of_get_flat_dt_prop(unsigned long node, const char *name, | ||
140 | unsigned long *size) | ||
141 | { | ||
142 | unsigned long p = node; | ||
143 | |||
144 | do { | ||
145 | u32 tag = *((u32 *)p); | ||
146 | u32 sz, noff; | ||
147 | const char *nstr; | ||
148 | |||
149 | p += 4; | ||
150 | if (tag == OF_DT_NOP) | ||
151 | continue; | ||
152 | if (tag != OF_DT_PROP) | ||
153 | return NULL; | ||
154 | |||
155 | sz = *((u32 *)p); | ||
156 | noff = *((u32 *)(p + 4)); | ||
157 | p += 8; | ||
158 | if (initial_boot_params->version < 0x10) | ||
159 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | ||
160 | |||
161 | nstr = find_flat_dt_string(noff); | ||
162 | if (nstr == NULL) { | ||
163 | printk(KERN_WARNING "Can't find property index" | ||
164 | " name !\n"); | ||
165 | return NULL; | ||
166 | } | ||
167 | if (strcmp(name, nstr) == 0) { | ||
168 | if (size) | ||
169 | *size = sz; | ||
170 | return (void *)p; | ||
171 | } | ||
172 | p += sz; | ||
173 | p = _ALIGN(p, 4); | ||
174 | } while (1); | ||
175 | } | ||
176 | |||
177 | int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) | ||
178 | { | ||
179 | const char *cp; | ||
180 | unsigned long cplen, l; | ||
181 | |||
182 | cp = of_get_flat_dt_prop(node, "compatible", &cplen); | ||
183 | if (cp == NULL) | ||
184 | return 0; | ||
185 | while (cplen > 0) { | ||
186 | if (strncasecmp(cp, compat, strlen(compat)) == 0) | ||
187 | return 1; | ||
188 | l = strlen(cp) + 1; | ||
189 | cp += l; | ||
190 | cplen -= l; | ||
191 | } | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | ||
197 | unsigned long align) | ||
198 | { | ||
199 | void *res; | ||
200 | |||
201 | *mem = _ALIGN(*mem, align); | ||
202 | res = (void *)*mem; | ||
203 | *mem += size; | ||
204 | |||
205 | return res; | ||
206 | } | ||
207 | |||
208 | static unsigned long __init unflatten_dt_node(unsigned long mem, | ||
209 | unsigned long *p, | ||
210 | struct device_node *dad, | ||
211 | struct device_node ***allnextpp, | ||
212 | unsigned long fpsize) | ||
213 | { | ||
214 | struct device_node *np; | ||
215 | struct property *pp, **prev_pp = NULL; | ||
216 | char *pathp; | ||
217 | u32 tag; | ||
218 | unsigned int l, allocl; | ||
219 | int has_name = 0; | ||
220 | int new_format = 0; | ||
221 | |||
222 | tag = *((u32 *)(*p)); | ||
223 | if (tag != OF_DT_BEGIN_NODE) { | ||
224 | printk("Weird tag at start of node: %x\n", tag); | ||
225 | return mem; | ||
226 | } | ||
227 | *p += 4; | ||
228 | pathp = (char *)*p; | ||
229 | l = allocl = strlen(pathp) + 1; | ||
230 | *p = _ALIGN(*p + l, 4); | ||
231 | |||
232 | /* version 0x10 has a more compact unit name here instead of the full | ||
233 | * path. we accumulate the full path size using "fpsize", we'll rebuild | ||
234 | * it later. We detect this because the first character of the name is | ||
235 | * not '/'. | ||
236 | */ | ||
237 | if ((*pathp) != '/') { | ||
238 | new_format = 1; | ||
239 | if (fpsize == 0) { | ||
240 | /* root node: special case. fpsize accounts for path | ||
241 | * plus terminating zero. root node only has '/', so | ||
242 | * fpsize should be 2, but we want to avoid the first | ||
243 | * level nodes to have two '/' so we use fpsize 1 here | ||
244 | */ | ||
245 | fpsize = 1; | ||
246 | allocl = 2; | ||
247 | } else { | ||
248 | /* account for '/' and path size minus terminal 0 | ||
249 | * already in 'l' | ||
250 | */ | ||
251 | fpsize += l; | ||
252 | allocl = fpsize; | ||
253 | } | ||
254 | } | ||
255 | |||
256 | np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, | ||
257 | __alignof__(struct device_node)); | ||
258 | if (allnextpp) { | ||
259 | memset(np, 0, sizeof(*np)); | ||
260 | np->full_name = ((char *)np) + sizeof(struct device_node); | ||
261 | if (new_format) { | ||
262 | char *p2 = np->full_name; | ||
263 | /* rebuild full path for new format */ | ||
264 | if (dad && dad->parent) { | ||
265 | strcpy(p2, dad->full_name); | ||
266 | #ifdef DEBUG | ||
267 | if ((strlen(p2) + l + 1) != allocl) { | ||
268 | pr_debug("%s: p: %d, l: %d, a: %d\n", | ||
269 | pathp, (int)strlen(p2), | ||
270 | l, allocl); | ||
271 | } | ||
272 | #endif | ||
273 | p2 += strlen(p2); | ||
274 | } | ||
275 | *(p2++) = '/'; | ||
276 | memcpy(p2, pathp, l); | ||
277 | } else | ||
278 | memcpy(np->full_name, pathp, l); | ||
279 | prev_pp = &np->properties; | ||
280 | **allnextpp = np; | ||
281 | *allnextpp = &np->allnext; | ||
282 | if (dad != NULL) { | ||
283 | np->parent = dad; | ||
284 | /* we temporarily use the next field as `last_child'*/ | ||
285 | if (dad->next == NULL) | ||
286 | dad->child = np; | ||
287 | else | ||
288 | dad->next->sibling = np; | ||
289 | dad->next = np; | ||
290 | } | ||
291 | kref_init(&np->kref); | ||
292 | } | ||
293 | while (1) { | ||
294 | u32 sz, noff; | ||
295 | char *pname; | ||
296 | |||
297 | tag = *((u32 *)(*p)); | ||
298 | if (tag == OF_DT_NOP) { | ||
299 | *p += 4; | ||
300 | continue; | ||
301 | } | ||
302 | if (tag != OF_DT_PROP) | ||
303 | break; | ||
304 | *p += 4; | ||
305 | sz = *((u32 *)(*p)); | ||
306 | noff = *((u32 *)((*p) + 4)); | ||
307 | *p += 8; | ||
308 | if (initial_boot_params->version < 0x10) | ||
309 | *p = _ALIGN(*p, sz >= 8 ? 8 : 4); | ||
310 | |||
311 | pname = find_flat_dt_string(noff); | ||
312 | if (pname == NULL) { | ||
313 | printk(KERN_INFO | ||
314 | "Can't find property name in list !\n"); | ||
315 | break; | ||
316 | } | ||
317 | if (strcmp(pname, "name") == 0) | ||
318 | has_name = 1; | ||
319 | l = strlen(pname) + 1; | ||
320 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), | ||
321 | __alignof__(struct property)); | ||
322 | if (allnextpp) { | ||
323 | if (strcmp(pname, "linux,phandle") == 0) { | ||
324 | np->node = *((u32 *)*p); | ||
325 | if (np->linux_phandle == 0) | ||
326 | np->linux_phandle = np->node; | ||
327 | } | ||
328 | if (strcmp(pname, "ibm,phandle") == 0) | ||
329 | np->linux_phandle = *((u32 *)*p); | ||
330 | pp->name = pname; | ||
331 | pp->length = sz; | ||
332 | pp->value = (void *)*p; | ||
333 | *prev_pp = pp; | ||
334 | prev_pp = &pp->next; | ||
335 | } | ||
336 | *p = _ALIGN((*p) + sz, 4); | ||
337 | } | ||
338 | /* with version 0x10 we may not have the name property, recreate | ||
339 | * it here from the unit name if absent | ||
340 | */ | ||
341 | if (!has_name) { | ||
342 | char *p1 = pathp, *ps = pathp, *pa = NULL; | ||
343 | int sz; | ||
344 | |||
345 | while (*p1) { | ||
346 | if ((*p1) == '@') | ||
347 | pa = p1; | ||
348 | if ((*p1) == '/') | ||
349 | ps = p1 + 1; | ||
350 | p1++; | ||
351 | } | ||
352 | if (pa < ps) | ||
353 | pa = p1; | ||
354 | sz = (pa - ps) + 1; | ||
355 | pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, | ||
356 | __alignof__(struct property)); | ||
357 | if (allnextpp) { | ||
358 | pp->name = "name"; | ||
359 | pp->length = sz; | ||
360 | pp->value = pp + 1; | ||
361 | *prev_pp = pp; | ||
362 | prev_pp = &pp->next; | ||
363 | memcpy(pp->value, ps, sz - 1); | ||
364 | ((char *)pp->value)[sz - 1] = 0; | ||
365 | pr_debug("fixed up name for %s -> %s\n", pathp, | ||
366 | (char *)pp->value); | ||
367 | } | ||
368 | } | ||
369 | if (allnextpp) { | ||
370 | *prev_pp = NULL; | ||
371 | np->name = of_get_property(np, "name", NULL); | ||
372 | np->type = of_get_property(np, "device_type", NULL); | ||
373 | |||
374 | if (!np->name) | ||
375 | np->name = "<NULL>"; | ||
376 | if (!np->type) | ||
377 | np->type = "<NULL>"; | ||
378 | } | ||
379 | while (tag == OF_DT_BEGIN_NODE) { | ||
380 | mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); | ||
381 | tag = *((u32 *)(*p)); | ||
382 | } | ||
383 | if (tag != OF_DT_END_NODE) { | ||
384 | printk(KERN_INFO "Weird tag at end of node: %x\n", tag); | ||
385 | return mem; | ||
386 | } | ||
387 | *p += 4; | ||
388 | return mem; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * unflattens the device-tree passed by the firmware, creating the | ||
393 | * tree of struct device_node. It also fills the "name" and "type" | ||
394 | * pointers of the nodes so the normal device-tree walking functions | ||
395 | * can be used (this used to be done by finish_device_tree) | ||
396 | */ | ||
397 | void __init unflatten_device_tree(void) | ||
398 | { | ||
399 | unsigned long start, mem, size; | ||
400 | struct device_node **allnextp = &allnodes; | ||
401 | |||
402 | pr_debug(" -> unflatten_device_tree()\n"); | ||
403 | |||
404 | /* First pass, scan for size */ | ||
405 | start = ((unsigned long)initial_boot_params) + | ||
406 | initial_boot_params->off_dt_struct; | ||
407 | size = unflatten_dt_node(0, &start, NULL, NULL, 0); | ||
408 | size = (size | 3) + 1; | ||
409 | |||
410 | pr_debug(" size is %lx, allocating...\n", size); | ||
411 | |||
412 | /* Allocate memory for the expanded device tree */ | ||
413 | mem = lmb_alloc(size + 4, __alignof__(struct device_node)); | ||
414 | mem = (unsigned long) __va(mem); | ||
415 | |||
416 | ((u32 *)mem)[size / 4] = 0xdeadbeef; | ||
417 | |||
418 | pr_debug(" unflattening %lx...\n", mem); | ||
419 | |||
420 | /* Second pass, do actual unflattening */ | ||
421 | start = ((unsigned long)initial_boot_params) + | ||
422 | initial_boot_params->off_dt_struct; | ||
423 | unflatten_dt_node(mem, &start, NULL, &allnextp, 0); | ||
424 | if (*((u32 *)start) != OF_DT_END) | ||
425 | printk(KERN_WARNING "Weird tag at end of tree: %08x\n", | ||
426 | *((u32 *)start)); | ||
427 | if (((u32 *)mem)[size / 4] != 0xdeadbeef) | ||
428 | printk(KERN_WARNING "End of tree marker overwritten: %08x\n", | ||
429 | ((u32 *)mem)[size / 4]); | ||
430 | *allnextp = NULL; | ||
431 | |||
432 | /* Get pointer to OF "/chosen" node for use everywhere */ | ||
433 | of_chosen = of_find_node_by_path("/chosen"); | ||
434 | if (of_chosen == NULL) | ||
435 | of_chosen = of_find_node_by_path("/chosen@0"); | ||
436 | |||
437 | pr_debug(" <- unflatten_device_tree()\n"); | ||
438 | } | ||
439 | |||
440 | #define early_init_dt_scan_drconf_memory(node) 0 | ||
441 | |||
442 | static int __init early_init_dt_scan_cpus(unsigned long node, | ||
443 | const char *uname, int depth, | ||
444 | void *data) | ||
445 | { | ||
446 | static int logical_cpuid; | ||
447 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | ||
448 | const u32 *intserv; | ||
449 | int i, nthreads; | ||
450 | int found = 0; | ||
451 | |||
452 | /* We are scanning "cpu" nodes only */ | ||
453 | if (type == NULL || strcmp(type, "cpu") != 0) | ||
454 | return 0; | ||
455 | |||
456 | /* Get physical cpuid */ | ||
457 | intserv = of_get_flat_dt_prop(node, "reg", NULL); | ||
458 | nthreads = 1; | ||
459 | |||
460 | /* | ||
461 | * Now see if any of these threads match our boot cpu. | ||
462 | * NOTE: This must match the parsing done in smp_setup_cpu_maps. | ||
463 | */ | ||
464 | for (i = 0; i < nthreads; i++) { | ||
465 | /* | ||
466 | * version 2 of the kexec param format adds the phys cpuid of | ||
467 | * booted proc. | ||
468 | */ | ||
469 | if (initial_boot_params && initial_boot_params->version >= 2) { | ||
470 | if (intserv[i] == | ||
471 | initial_boot_params->boot_cpuid_phys) { | ||
472 | found = 1; | ||
473 | break; | ||
474 | } | ||
475 | } else { | ||
476 | /* | ||
477 | * Check if it's the boot-cpu, set it's hw index now, | ||
478 | * unfortunately this format did not support booting | ||
479 | * off secondary threads. | ||
480 | */ | ||
481 | if (of_get_flat_dt_prop(node, | ||
482 | "linux,boot-cpu", NULL) != NULL) { | ||
483 | found = 1; | ||
484 | break; | ||
485 | } | ||
486 | } | ||
487 | |||
488 | #ifdef CONFIG_SMP | ||
489 | /* logical cpu id is always 0 on UP kernels */ | ||
490 | logical_cpuid++; | ||
491 | #endif | ||
492 | } | ||
493 | |||
494 | if (found) { | ||
495 | pr_debug("boot cpu: logical %d physical %d\n", logical_cpuid, | ||
496 | intserv[i]); | ||
497 | boot_cpuid = logical_cpuid; | ||
498 | } | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | #ifdef CONFIG_BLK_DEV_INITRD | ||
504 | static void __init early_init_dt_check_for_initrd(unsigned long node) | ||
505 | { | ||
506 | unsigned long l; | ||
507 | u32 *prop; | ||
508 | |||
509 | pr_debug("Looking for initrd properties... "); | ||
510 | |||
511 | prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l); | ||
512 | if (prop) { | ||
513 | initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4)); | ||
514 | |||
515 | prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l); | ||
516 | if (prop) { | ||
517 | initrd_end = (unsigned long) | ||
518 | __va(of_read_ulong(prop, l/4)); | ||
519 | initrd_below_start_ok = 1; | ||
520 | } else { | ||
521 | initrd_start = 0; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | pr_debug("initrd_start=0x%lx initrd_end=0x%lx\n", | ||
526 | initrd_start, initrd_end); | ||
527 | } | ||
528 | #else | ||
529 | static inline void early_init_dt_check_for_initrd(unsigned long node) | ||
530 | { | ||
531 | } | ||
532 | #endif /* CONFIG_BLK_DEV_INITRD */ | ||
533 | |||
534 | static int __init early_init_dt_scan_chosen(unsigned long node, | ||
535 | const char *uname, int depth, void *data) | ||
536 | { | ||
537 | unsigned long l; | ||
538 | char *p; | ||
539 | |||
540 | pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); | ||
541 | |||
542 | if (depth != 1 || | ||
543 | (strcmp(uname, "chosen") != 0 && | ||
544 | strcmp(uname, "chosen@0") != 0)) | ||
545 | return 0; | ||
546 | |||
547 | #ifdef CONFIG_KEXEC | ||
548 | lprop = (u64 *)of_get_flat_dt_prop(node, | ||
549 | "linux,crashkernel-base", NULL); | ||
550 | if (lprop) | ||
551 | crashk_res.start = *lprop; | ||
552 | |||
553 | lprop = (u64 *)of_get_flat_dt_prop(node, | ||
554 | "linux,crashkernel-size", NULL); | ||
555 | if (lprop) | ||
556 | crashk_res.end = crashk_res.start + *lprop - 1; | ||
557 | #endif | ||
558 | |||
559 | early_init_dt_check_for_initrd(node); | ||
560 | |||
561 | /* Retreive command line */ | ||
562 | p = of_get_flat_dt_prop(node, "bootargs", &l); | ||
563 | if (p != NULL && l > 0) | ||
564 | strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE)); | ||
565 | |||
566 | #ifdef CONFIG_CMDLINE | ||
567 | if (p == NULL || l == 0 || (l == 1 && (*p) == 0)) | ||
568 | strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE); | ||
569 | #endif /* CONFIG_CMDLINE */ | ||
570 | |||
571 | pr_debug("Command line is: %s\n", cmd_line); | ||
572 | |||
573 | /* break now */ | ||
574 | return 1; | ||
575 | } | ||
576 | |||
577 | static int __init early_init_dt_scan_root(unsigned long node, | ||
578 | const char *uname, int depth, void *data) | ||
579 | { | ||
580 | u32 *prop; | ||
581 | |||
582 | if (depth != 0) | ||
583 | return 0; | ||
584 | |||
585 | prop = of_get_flat_dt_prop(node, "#size-cells", NULL); | ||
586 | dt_root_size_cells = (prop == NULL) ? 1 : *prop; | ||
587 | pr_debug("dt_root_size_cells = %x\n", dt_root_size_cells); | ||
588 | |||
589 | prop = of_get_flat_dt_prop(node, "#address-cells", NULL); | ||
590 | dt_root_addr_cells = (prop == NULL) ? 2 : *prop; | ||
591 | pr_debug("dt_root_addr_cells = %x\n", dt_root_addr_cells); | ||
592 | |||
593 | /* break now */ | ||
594 | return 1; | ||
595 | } | ||
596 | |||
597 | static u64 __init dt_mem_next_cell(int s, cell_t **cellp) | ||
598 | { | ||
599 | cell_t *p = *cellp; | ||
600 | |||
601 | *cellp = p + s; | ||
602 | return of_read_number(p, s); | ||
603 | } | ||
604 | |||
605 | static int __init early_init_dt_scan_memory(unsigned long node, | ||
606 | const char *uname, int depth, void *data) | ||
607 | { | ||
608 | char *type = of_get_flat_dt_prop(node, "device_type", NULL); | ||
609 | cell_t *reg, *endp; | ||
610 | unsigned long l; | ||
611 | |||
612 | /* Look for the ibm,dynamic-reconfiguration-memory node */ | ||
613 | /* if (depth == 1 && | ||
614 | strcmp(uname, "ibm,dynamic-reconfiguration-memory") == 0) | ||
615 | return early_init_dt_scan_drconf_memory(node); | ||
616 | */ | ||
617 | /* We are scanning "memory" nodes only */ | ||
618 | if (type == NULL) { | ||
619 | /* | ||
620 | * The longtrail doesn't have a device_type on the | ||
621 | * /memory node, so look for the node called /memory@0. | ||
622 | */ | ||
623 | if (depth != 1 || strcmp(uname, "memory@0") != 0) | ||
624 | return 0; | ||
625 | } else if (strcmp(type, "memory") != 0) | ||
626 | return 0; | ||
627 | |||
628 | reg = (cell_t *)of_get_flat_dt_prop(node, "linux,usable-memory", &l); | ||
629 | if (reg == NULL) | ||
630 | reg = (cell_t *)of_get_flat_dt_prop(node, "reg", &l); | ||
631 | if (reg == NULL) | ||
632 | return 0; | ||
633 | |||
634 | endp = reg + (l / sizeof(cell_t)); | ||
635 | |||
636 | pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n", | ||
637 | uname, l, reg[0], reg[1], reg[2], reg[3]); | ||
638 | |||
639 | while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { | ||
640 | u64 base, size; | ||
641 | |||
642 | base = dt_mem_next_cell(dt_root_addr_cells, ®); | ||
643 | size = dt_mem_next_cell(dt_root_size_cells, ®); | ||
644 | |||
645 | if (size == 0) | ||
646 | continue; | ||
647 | pr_debug(" - %llx , %llx\n", (unsigned long long)base, | ||
648 | (unsigned long long)size); | ||
649 | |||
650 | lmb_add(base, size); | ||
651 | } | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | #ifdef CONFIG_PHYP_DUMP | ||
656 | /** | ||
657 | * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg | ||
658 | * | ||
659 | * Function to find the largest size we need to reserve | ||
660 | * during early boot process. | ||
661 | * | ||
662 | * It either looks for boot param and returns that OR | ||
663 | * returns larger of 256 or 5% rounded down to multiples of 256MB. | ||
664 | * | ||
665 | */ | ||
666 | static inline unsigned long phyp_dump_calculate_reserve_size(void) | ||
667 | { | ||
668 | unsigned long tmp; | ||
669 | |||
670 | if (phyp_dump_info->reserve_bootvar) | ||
671 | return phyp_dump_info->reserve_bootvar; | ||
672 | |||
673 | /* divide by 20 to get 5% of value */ | ||
674 | tmp = lmb_end_of_DRAM(); | ||
675 | do_div(tmp, 20); | ||
676 | |||
677 | /* round it down in multiples of 256 */ | ||
678 | tmp = tmp & ~0x0FFFFFFFUL; | ||
679 | |||
680 | return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); | ||
681 | } | ||
682 | |||
683 | /** | ||
684 | * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory | ||
685 | * | ||
686 | * This routine may reserve memory regions in the kernel only | ||
687 | * if the system is supported and a dump was taken in last | ||
688 | * boot instance or if the hardware is supported and the | ||
689 | * scratch area needs to be setup. In other instances it returns | ||
690 | * without reserving anything. The memory in case of dump being | ||
691 | * active is freed when the dump is collected (by userland tools). | ||
692 | */ | ||
693 | static void __init phyp_dump_reserve_mem(void) | ||
694 | { | ||
695 | unsigned long base, size; | ||
696 | unsigned long variable_reserve_size; | ||
697 | |||
698 | if (!phyp_dump_info->phyp_dump_configured) { | ||
699 | printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); | ||
700 | return; | ||
701 | } | ||
702 | |||
703 | if (!phyp_dump_info->phyp_dump_at_boot) { | ||
704 | printk(KERN_INFO "Phyp-dump disabled at boot time\n"); | ||
705 | return; | ||
706 | } | ||
707 | |||
708 | variable_reserve_size = phyp_dump_calculate_reserve_size(); | ||
709 | |||
710 | if (phyp_dump_info->phyp_dump_is_active) { | ||
711 | /* Reserve *everything* above RMR.Area freed by userland tools*/ | ||
712 | base = variable_reserve_size; | ||
713 | size = lmb_end_of_DRAM() - base; | ||
714 | |||
715 | /* XXX crashed_ram_end is wrong, since it may be beyond | ||
716 | * the memory_limit, it will need to be adjusted. */ | ||
717 | lmb_reserve(base, size); | ||
718 | |||
719 | phyp_dump_info->init_reserve_start = base; | ||
720 | phyp_dump_info->init_reserve_size = size; | ||
721 | } else { | ||
722 | size = phyp_dump_info->cpu_state_size + | ||
723 | phyp_dump_info->hpte_region_size + | ||
724 | variable_reserve_size; | ||
725 | base = lmb_end_of_DRAM() - size; | ||
726 | lmb_reserve(base, size); | ||
727 | phyp_dump_info->init_reserve_start = base; | ||
728 | phyp_dump_info->init_reserve_size = size; | ||
729 | } | ||
730 | } | ||
731 | #else | ||
732 | static inline void __init phyp_dump_reserve_mem(void) {} | ||
733 | #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ | ||
734 | |||
735 | #ifdef CONFIG_EARLY_PRINTK | ||
736 | /* MS this is Microblaze specifig function */ | ||
737 | static int __init early_init_dt_scan_serial(unsigned long node, | ||
738 | const char *uname, int depth, void *data) | ||
739 | { | ||
740 | unsigned long l; | ||
741 | char *p; | ||
742 | int *addr; | ||
743 | |||
744 | pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); | ||
745 | |||
746 | /* find all serial nodes */ | ||
747 | if (strncmp(uname, "serial", 6) != 0) | ||
748 | return 0; | ||
749 | |||
750 | early_init_dt_check_for_initrd(node); | ||
751 | |||
752 | /* find compatible node with uartlite */ | ||
753 | p = of_get_flat_dt_prop(node, "compatible", &l); | ||
754 | if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) && | ||
755 | (strncmp(p, "xlnx,opb-uartlite", 17) != 0)) | ||
756 | return 0; | ||
757 | |||
758 | addr = of_get_flat_dt_prop(node, "reg", &l); | ||
759 | return *addr; /* return address */ | ||
760 | } | ||
761 | |||
762 | /* this function is looking for early uartlite console - Microblaze specific */ | ||
763 | int __init early_uartlite_console(void) | ||
764 | { | ||
765 | return of_scan_flat_dt(early_init_dt_scan_serial, NULL); | ||
766 | } | ||
767 | #endif | ||
768 | |||
769 | void __init early_init_devtree(void *params) | ||
770 | { | ||
771 | pr_debug(" -> early_init_devtree(%p)\n", params); | ||
772 | |||
773 | /* Setup flat device-tree pointer */ | ||
774 | initial_boot_params = params; | ||
775 | |||
776 | #ifdef CONFIG_PHYP_DUMP | ||
777 | /* scan tree to see if dump occured during last boot */ | ||
778 | of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); | ||
779 | #endif | ||
780 | |||
781 | /* Retrieve various informations from the /chosen node of the | ||
782 | * device-tree, including the platform type, initrd location and | ||
783 | * size, TCE reserve, and more ... | ||
784 | */ | ||
785 | of_scan_flat_dt(early_init_dt_scan_chosen, NULL); | ||
786 | |||
787 | /* Scan memory nodes and rebuild LMBs */ | ||
788 | lmb_init(); | ||
789 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | ||
790 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||
791 | |||
792 | /* Save command line for /proc/cmdline and then parse parameters */ | ||
793 | strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); | ||
794 | parse_early_param(); | ||
795 | |||
796 | lmb_analyze(); | ||
797 | |||
798 | pr_debug("Phys. mem: %lx\n", (unsigned long) lmb_phys_mem_size()); | ||
799 | |||
800 | pr_debug("Scanning CPUs ...\n"); | ||
801 | |||
802 | /* Retreive CPU related informations from the flat tree | ||
803 | * (altivec support, boot CPU ID, ...) | ||
804 | */ | ||
805 | of_scan_flat_dt(early_init_dt_scan_cpus, NULL); | ||
806 | |||
807 | pr_debug(" <- early_init_devtree()\n"); | ||
808 | } | ||
809 | |||
810 | /** | ||
811 | * Indicates whether the root node has a given value in its | ||
812 | * compatible property. | ||
813 | */ | ||
814 | int machine_is_compatible(const char *compat) | ||
815 | { | ||
816 | struct device_node *root; | ||
817 | int rc = 0; | ||
818 | |||
819 | root = of_find_node_by_path("/"); | ||
820 | if (root) { | ||
821 | rc = of_device_is_compatible(root, compat); | ||
822 | of_node_put(root); | ||
823 | } | ||
824 | return rc; | ||
825 | } | ||
826 | EXPORT_SYMBOL(machine_is_compatible); | ||
827 | |||
828 | /******* | ||
829 | * | ||
830 | * New implementation of the OF "find" APIs, return a refcounted | ||
831 | * object, call of_node_put() when done. The device tree and list | ||
832 | * are protected by a rw_lock. | ||
833 | * | ||
834 | * Note that property management will need some locking as well, | ||
835 | * this isn't dealt with yet. | ||
836 | * | ||
837 | *******/ | ||
838 | |||
839 | /** | ||
840 | * of_find_node_by_phandle - Find a node given a phandle | ||
841 | * @handle: phandle of the node to find | ||
842 | * | ||
843 | * Returns a node pointer with refcount incremented, use | ||
844 | * of_node_put() on it when done. | ||
845 | */ | ||
846 | struct device_node *of_find_node_by_phandle(phandle handle) | ||
847 | { | ||
848 | struct device_node *np; | ||
849 | |||
850 | read_lock(&devtree_lock); | ||
851 | for (np = allnodes; np != NULL; np = np->allnext) | ||
852 | if (np->linux_phandle == handle) | ||
853 | break; | ||
854 | of_node_get(np); | ||
855 | read_unlock(&devtree_lock); | ||
856 | return np; | ||
857 | } | ||
858 | EXPORT_SYMBOL(of_find_node_by_phandle); | ||
859 | |||
860 | /** | ||
861 | * of_find_all_nodes - Get next node in global list | ||
862 | * @prev: Previous node or NULL to start iteration | ||
863 | * of_node_put() will be called on it | ||
864 | * | ||
865 | * Returns a node pointer with refcount incremented, use | ||
866 | * of_node_put() on it when done. | ||
867 | */ | ||
868 | struct device_node *of_find_all_nodes(struct device_node *prev) | ||
869 | { | ||
870 | struct device_node *np; | ||
871 | |||
872 | read_lock(&devtree_lock); | ||
873 | np = prev ? prev->allnext : allnodes; | ||
874 | for (; np != NULL; np = np->allnext) | ||
875 | if (of_node_get(np)) | ||
876 | break; | ||
877 | of_node_put(prev); | ||
878 | read_unlock(&devtree_lock); | ||
879 | return np; | ||
880 | } | ||
881 | EXPORT_SYMBOL(of_find_all_nodes); | ||
882 | |||
883 | /** | ||
884 | * of_node_get - Increment refcount of a node | ||
885 | * @node: Node to inc refcount, NULL is supported to | ||
886 | * simplify writing of callers | ||
887 | * | ||
888 | * Returns node. | ||
889 | */ | ||
890 | struct device_node *of_node_get(struct device_node *node) | ||
891 | { | ||
892 | if (node) | ||
893 | kref_get(&node->kref); | ||
894 | return node; | ||
895 | } | ||
896 | EXPORT_SYMBOL(of_node_get); | ||
897 | |||
898 | static inline struct device_node *kref_to_device_node(struct kref *kref) | ||
899 | { | ||
900 | return container_of(kref, struct device_node, kref); | ||
901 | } | ||
902 | |||
903 | /** | ||
904 | * of_node_release - release a dynamically allocated node | ||
905 | * @kref: kref element of the node to be released | ||
906 | * | ||
907 | * In of_node_put() this function is passed to kref_put() | ||
908 | * as the destructor. | ||
909 | */ | ||
910 | static void of_node_release(struct kref *kref) | ||
911 | { | ||
912 | struct device_node *node = kref_to_device_node(kref); | ||
913 | struct property *prop = node->properties; | ||
914 | |||
915 | /* We should never be releasing nodes that haven't been detached. */ | ||
916 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
917 | printk(KERN_INFO "WARNING: Bad of_node_put() on %s\n", | ||
918 | node->full_name); | ||
919 | dump_stack(); | ||
920 | kref_init(&node->kref); | ||
921 | return; | ||
922 | } | ||
923 | |||
924 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
925 | return; | ||
926 | |||
927 | while (prop) { | ||
928 | struct property *next = prop->next; | ||
929 | kfree(prop->name); | ||
930 | kfree(prop->value); | ||
931 | kfree(prop); | ||
932 | prop = next; | ||
933 | |||
934 | if (!prop) { | ||
935 | prop = node->deadprops; | ||
936 | node->deadprops = NULL; | ||
937 | } | ||
938 | } | ||
939 | kfree(node->full_name); | ||
940 | kfree(node->data); | ||
941 | kfree(node); | ||
942 | } | ||
943 | |||
944 | /** | ||
945 | * of_node_put - Decrement refcount of a node | ||
946 | * @node: Node to dec refcount, NULL is supported to | ||
947 | * simplify writing of callers | ||
948 | * | ||
949 | */ | ||
950 | void of_node_put(struct device_node *node) | ||
951 | { | ||
952 | if (node) | ||
953 | kref_put(&node->kref, of_node_release); | ||
954 | } | ||
955 | EXPORT_SYMBOL(of_node_put); | ||
956 | |||
957 | /* | ||
958 | * Plug a device node into the tree and global list. | ||
959 | */ | ||
960 | void of_attach_node(struct device_node *np) | ||
961 | { | ||
962 | unsigned long flags; | ||
963 | |||
964 | write_lock_irqsave(&devtree_lock, flags); | ||
965 | np->sibling = np->parent->child; | ||
966 | np->allnext = allnodes; | ||
967 | np->parent->child = np; | ||
968 | allnodes = np; | ||
969 | write_unlock_irqrestore(&devtree_lock, flags); | ||
970 | } | ||
971 | |||
972 | /* | ||
973 | * "Unplug" a node from the device tree. The caller must hold | ||
974 | * a reference to the node. The memory associated with the node | ||
975 | * is not freed until its refcount goes to zero. | ||
976 | */ | ||
977 | void of_detach_node(struct device_node *np) | ||
978 | { | ||
979 | struct device_node *parent; | ||
980 | unsigned long flags; | ||
981 | |||
982 | write_lock_irqsave(&devtree_lock, flags); | ||
983 | |||
984 | parent = np->parent; | ||
985 | if (!parent) | ||
986 | goto out_unlock; | ||
987 | |||
988 | if (allnodes == np) | ||
989 | allnodes = np->allnext; | ||
990 | else { | ||
991 | struct device_node *prev; | ||
992 | for (prev = allnodes; | ||
993 | prev->allnext != np; | ||
994 | prev = prev->allnext) | ||
995 | ; | ||
996 | prev->allnext = np->allnext; | ||
997 | } | ||
998 | |||
999 | if (parent->child == np) | ||
1000 | parent->child = np->sibling; | ||
1001 | else { | ||
1002 | struct device_node *prevsib; | ||
1003 | for (prevsib = np->parent->child; | ||
1004 | prevsib->sibling != np; | ||
1005 | prevsib = prevsib->sibling) | ||
1006 | ; | ||
1007 | prevsib->sibling = np->sibling; | ||
1008 | } | ||
1009 | |||
1010 | of_node_set_flag(np, OF_DETACHED); | ||
1011 | |||
1012 | out_unlock: | ||
1013 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1014 | } | ||
1015 | |||
1016 | /* | ||
1017 | * Add a property to a node | ||
1018 | */ | ||
1019 | int prom_add_property(struct device_node *np, struct property *prop) | ||
1020 | { | ||
1021 | struct property **next; | ||
1022 | unsigned long flags; | ||
1023 | |||
1024 | prop->next = NULL; | ||
1025 | write_lock_irqsave(&devtree_lock, flags); | ||
1026 | next = &np->properties; | ||
1027 | while (*next) { | ||
1028 | if (strcmp(prop->name, (*next)->name) == 0) { | ||
1029 | /* duplicate ! don't insert it */ | ||
1030 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1031 | return -1; | ||
1032 | } | ||
1033 | next = &(*next)->next; | ||
1034 | } | ||
1035 | *next = prop; | ||
1036 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1037 | |||
1038 | #ifdef CONFIG_PROC_DEVICETREE | ||
1039 | /* try to add to proc as well if it was initialized */ | ||
1040 | if (np->pde) | ||
1041 | proc_device_tree_add_prop(np->pde, prop); | ||
1042 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1043 | |||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | /* | ||
1048 | * Remove a property from a node. Note that we don't actually | ||
1049 | * remove it, since we have given out who-knows-how-many pointers | ||
1050 | * to the data using get-property. Instead we just move the property | ||
1051 | * to the "dead properties" list, so it won't be found any more. | ||
1052 | */ | ||
1053 | int prom_remove_property(struct device_node *np, struct property *prop) | ||
1054 | { | ||
1055 | struct property **next; | ||
1056 | unsigned long flags; | ||
1057 | int found = 0; | ||
1058 | |||
1059 | write_lock_irqsave(&devtree_lock, flags); | ||
1060 | next = &np->properties; | ||
1061 | while (*next) { | ||
1062 | if (*next == prop) { | ||
1063 | /* found the node */ | ||
1064 | *next = prop->next; | ||
1065 | prop->next = np->deadprops; | ||
1066 | np->deadprops = prop; | ||
1067 | found = 1; | ||
1068 | break; | ||
1069 | } | ||
1070 | next = &(*next)->next; | ||
1071 | } | ||
1072 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1073 | |||
1074 | if (!found) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | #ifdef CONFIG_PROC_DEVICETREE | ||
1078 | /* try to remove the proc node as well */ | ||
1079 | if (np->pde) | ||
1080 | proc_device_tree_remove_prop(np->pde, prop); | ||
1081 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1082 | |||
1083 | return 0; | ||
1084 | } | ||
1085 | |||
1086 | /* | ||
1087 | * Update a property in a node. Note that we don't actually | ||
1088 | * remove it, since we have given out who-knows-how-many pointers | ||
1089 | * to the data using get-property. Instead we just move the property | ||
1090 | * to the "dead properties" list, and add the new property to the | ||
1091 | * property list | ||
1092 | */ | ||
1093 | int prom_update_property(struct device_node *np, | ||
1094 | struct property *newprop, | ||
1095 | struct property *oldprop) | ||
1096 | { | ||
1097 | struct property **next; | ||
1098 | unsigned long flags; | ||
1099 | int found = 0; | ||
1100 | |||
1101 | write_lock_irqsave(&devtree_lock, flags); | ||
1102 | next = &np->properties; | ||
1103 | while (*next) { | ||
1104 | if (*next == oldprop) { | ||
1105 | /* found the node */ | ||
1106 | newprop->next = oldprop->next; | ||
1107 | *next = newprop; | ||
1108 | oldprop->next = np->deadprops; | ||
1109 | np->deadprops = oldprop; | ||
1110 | found = 1; | ||
1111 | break; | ||
1112 | } | ||
1113 | next = &(*next)->next; | ||
1114 | } | ||
1115 | write_unlock_irqrestore(&devtree_lock, flags); | ||
1116 | |||
1117 | if (!found) | ||
1118 | return -ENODEV; | ||
1119 | |||
1120 | #ifdef CONFIG_PROC_DEVICETREE | ||
1121 | /* try to add to proc as well if it was initialized */ | ||
1122 | if (np->pde) | ||
1123 | proc_device_tree_update_prop(np->pde, newprop, oldprop); | ||
1124 | #endif /* CONFIG_PROC_DEVICETREE */ | ||
1125 | |||
1126 | return 0; | ||
1127 | } | ||
1128 | |||
1129 | #if defined(CONFIG_DEBUG_FS) && defined(DEBUG) | ||
1130 | static struct debugfs_blob_wrapper flat_dt_blob; | ||
1131 | |||
1132 | static int __init export_flat_device_tree(void) | ||
1133 | { | ||
1134 | struct dentry *d; | ||
1135 | |||
1136 | flat_dt_blob.data = initial_boot_params; | ||
1137 | flat_dt_blob.size = initial_boot_params->totalsize; | ||
1138 | |||
1139 | d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR, | ||
1140 | of_debugfs_root, &flat_dt_blob); | ||
1141 | if (!d) | ||
1142 | return 1; | ||
1143 | |||
1144 | return 0; | ||
1145 | } | ||
1146 | device_initcall(export_flat_device_tree); | ||
1147 | #endif | ||
diff --git a/arch/microblaze/kernel/prom_parse.c b/arch/microblaze/kernel/prom_parse.c new file mode 100644 index 000000000000..ae0352ecd5a9 --- /dev/null +++ b/arch/microblaze/kernel/prom_parse.c | |||
@@ -0,0 +1,1025 @@ | |||
1 | #undef DEBUG | ||
2 | |||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/string.h> | ||
5 | #include <linux/pci_regs.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <linux/ioport.h> | ||
8 | #include <linux/etherdevice.h> | ||
9 | #include <asm/prom.h> | ||
10 | #include <asm/pci-bridge.h> | ||
11 | |||
12 | #define PRu64 "%llx" | ||
13 | |||
14 | /* Max address size we deal with */ | ||
15 | #define OF_MAX_ADDR_CELLS 4 | ||
16 | #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ | ||
17 | (ns) > 0) | ||
18 | |||
19 | static struct of_bus *of_match_bus(struct device_node *np); | ||
20 | static int __of_address_to_resource(struct device_node *dev, | ||
21 | const u32 *addrp, u64 size, unsigned int flags, | ||
22 | struct resource *r); | ||
23 | |||
24 | /* Debug utility */ | ||
25 | #ifdef DEBUG | ||
26 | static void of_dump_addr(const char *s, const u32 *addr, int na) | ||
27 | { | ||
28 | printk(KERN_INFO "%s", s); | ||
29 | while (na--) | ||
30 | printk(KERN_INFO " %08x", *(addr++)); | ||
31 | printk(KERN_INFO "\n"); | ||
32 | } | ||
33 | #else | ||
34 | static void of_dump_addr(const char *s, const u32 *addr, int na) { } | ||
35 | #endif | ||
36 | |||
37 | /* Callbacks for bus specific translators */ | ||
38 | struct of_bus { | ||
39 | const char *name; | ||
40 | const char *addresses; | ||
41 | int (*match)(struct device_node *parent); | ||
42 | void (*count_cells)(struct device_node *child, | ||
43 | int *addrc, int *sizec); | ||
44 | u64 (*map)(u32 *addr, const u32 *range, | ||
45 | int na, int ns, int pna); | ||
46 | int (*translate)(u32 *addr, u64 offset, int na); | ||
47 | unsigned int (*get_flags)(const u32 *addr); | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * Default translator (generic bus) | ||
52 | */ | ||
53 | |||
54 | static void of_bus_default_count_cells(struct device_node *dev, | ||
55 | int *addrc, int *sizec) | ||
56 | { | ||
57 | if (addrc) | ||
58 | *addrc = of_n_addr_cells(dev); | ||
59 | if (sizec) | ||
60 | *sizec = of_n_size_cells(dev); | ||
61 | } | ||
62 | |||
63 | static u64 of_bus_default_map(u32 *addr, const u32 *range, | ||
64 | int na, int ns, int pna) | ||
65 | { | ||
66 | u64 cp, s, da; | ||
67 | |||
68 | cp = of_read_number(range, na); | ||
69 | s = of_read_number(range + na + pna, ns); | ||
70 | da = of_read_number(addr, na); | ||
71 | |||
72 | pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", | ||
73 | cp, s, da); | ||
74 | |||
75 | if (da < cp || da >= (cp + s)) | ||
76 | return OF_BAD_ADDR; | ||
77 | return da - cp; | ||
78 | } | ||
79 | |||
80 | static int of_bus_default_translate(u32 *addr, u64 offset, int na) | ||
81 | { | ||
82 | u64 a = of_read_number(addr, na); | ||
83 | memset(addr, 0, na * 4); | ||
84 | a += offset; | ||
85 | if (na > 1) | ||
86 | addr[na - 2] = a >> 32; | ||
87 | addr[na - 1] = a & 0xffffffffu; | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static unsigned int of_bus_default_get_flags(const u32 *addr) | ||
93 | { | ||
94 | return IORESOURCE_MEM; | ||
95 | } | ||
96 | |||
97 | #ifdef CONFIG_PCI | ||
98 | /* | ||
99 | * PCI bus specific translator | ||
100 | */ | ||
101 | |||
102 | static int of_bus_pci_match(struct device_node *np) | ||
103 | { | ||
104 | /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */ | ||
105 | return !strcmp(np->type, "pci") || !strcmp(np->type, "vci"); | ||
106 | } | ||
107 | |||
108 | static void of_bus_pci_count_cells(struct device_node *np, | ||
109 | int *addrc, int *sizec) | ||
110 | { | ||
111 | if (addrc) | ||
112 | *addrc = 3; | ||
113 | if (sizec) | ||
114 | *sizec = 2; | ||
115 | } | ||
116 | |||
117 | static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) | ||
118 | { | ||
119 | u64 cp, s, da; | ||
120 | |||
121 | /* Check address type match */ | ||
122 | if ((addr[0] ^ range[0]) & 0x03000000) | ||
123 | return OF_BAD_ADDR; | ||
124 | |||
125 | /* Read address values, skipping high cell */ | ||
126 | cp = of_read_number(range + 1, na - 1); | ||
127 | s = of_read_number(range + na + pna, ns); | ||
128 | da = of_read_number(addr + 1, na - 1); | ||
129 | |||
130 | pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); | ||
131 | |||
132 | if (da < cp || da >= (cp + s)) | ||
133 | return OF_BAD_ADDR; | ||
134 | return da - cp; | ||
135 | } | ||
136 | |||
137 | static int of_bus_pci_translate(u32 *addr, u64 offset, int na) | ||
138 | { | ||
139 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
140 | } | ||
141 | |||
142 | static unsigned int of_bus_pci_get_flags(const u32 *addr) | ||
143 | { | ||
144 | unsigned int flags = 0; | ||
145 | u32 w = addr[0]; | ||
146 | |||
147 | switch ((w >> 24) & 0x03) { | ||
148 | case 0x01: | ||
149 | flags |= IORESOURCE_IO; | ||
150 | break; | ||
151 | case 0x02: /* 32 bits */ | ||
152 | case 0x03: /* 64 bits */ | ||
153 | flags |= IORESOURCE_MEM; | ||
154 | break; | ||
155 | } | ||
156 | if (w & 0x40000000) | ||
157 | flags |= IORESOURCE_PREFETCH; | ||
158 | return flags; | ||
159 | } | ||
160 | |||
161 | const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, | ||
162 | unsigned int *flags) | ||
163 | { | ||
164 | const u32 *prop; | ||
165 | unsigned int psize; | ||
166 | struct device_node *parent; | ||
167 | struct of_bus *bus; | ||
168 | int onesize, i, na, ns; | ||
169 | |||
170 | /* Get parent & match bus type */ | ||
171 | parent = of_get_parent(dev); | ||
172 | if (parent == NULL) | ||
173 | return NULL; | ||
174 | bus = of_match_bus(parent); | ||
175 | if (strcmp(bus->name, "pci")) { | ||
176 | of_node_put(parent); | ||
177 | return NULL; | ||
178 | } | ||
179 | bus->count_cells(dev, &na, &ns); | ||
180 | of_node_put(parent); | ||
181 | if (!OF_CHECK_COUNTS(na, ns)) | ||
182 | return NULL; | ||
183 | |||
184 | /* Get "reg" or "assigned-addresses" property */ | ||
185 | prop = of_get_property(dev, bus->addresses, &psize); | ||
186 | if (prop == NULL) | ||
187 | return NULL; | ||
188 | psize /= 4; | ||
189 | |||
190 | onesize = na + ns; | ||
191 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
192 | if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { | ||
193 | if (size) | ||
194 | *size = of_read_number(prop + na, ns); | ||
195 | if (flags) | ||
196 | *flags = bus->get_flags(prop); | ||
197 | return prop; | ||
198 | } | ||
199 | return NULL; | ||
200 | } | ||
201 | EXPORT_SYMBOL(of_get_pci_address); | ||
202 | |||
203 | int of_pci_address_to_resource(struct device_node *dev, int bar, | ||
204 | struct resource *r) | ||
205 | { | ||
206 | const u32 *addrp; | ||
207 | u64 size; | ||
208 | unsigned int flags; | ||
209 | |||
210 | addrp = of_get_pci_address(dev, bar, &size, &flags); | ||
211 | if (addrp == NULL) | ||
212 | return -EINVAL; | ||
213 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
214 | } | ||
215 | EXPORT_SYMBOL_GPL(of_pci_address_to_resource); | ||
216 | |||
217 | static u8 of_irq_pci_swizzle(u8 slot, u8 pin) | ||
218 | { | ||
219 | return (((pin - 1) + slot) % 4) + 1; | ||
220 | } | ||
221 | |||
222 | int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq) | ||
223 | { | ||
224 | struct device_node *dn, *ppnode; | ||
225 | struct pci_dev *ppdev; | ||
226 | u32 lspec; | ||
227 | u32 laddr[3]; | ||
228 | u8 pin; | ||
229 | int rc; | ||
230 | |||
231 | /* Check if we have a device node, if yes, fallback to standard OF | ||
232 | * parsing | ||
233 | */ | ||
234 | dn = pci_device_to_OF_node(pdev); | ||
235 | if (dn) | ||
236 | return of_irq_map_one(dn, 0, out_irq); | ||
237 | |||
238 | /* Ok, we don't, time to have fun. Let's start by building up an | ||
239 | * interrupt spec. we assume #interrupt-cells is 1, which is standard | ||
240 | * for PCI. If you do different, then don't use that routine. | ||
241 | */ | ||
242 | rc = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin); | ||
243 | if (rc != 0) | ||
244 | return rc; | ||
245 | /* No pin, exit */ | ||
246 | if (pin == 0) | ||
247 | return -ENODEV; | ||
248 | |||
249 | /* Now we walk up the PCI tree */ | ||
250 | lspec = pin; | ||
251 | for (;;) { | ||
252 | /* Get the pci_dev of our parent */ | ||
253 | ppdev = pdev->bus->self; | ||
254 | |||
255 | /* Ouch, it's a host bridge... */ | ||
256 | if (ppdev == NULL) { | ||
257 | struct pci_controller *host; | ||
258 | host = pci_bus_to_host(pdev->bus); | ||
259 | ppnode = host ? host->arch_data : NULL; | ||
260 | /* No node for host bridge ? give up */ | ||
261 | if (ppnode == NULL) | ||
262 | return -EINVAL; | ||
263 | } else | ||
264 | /* We found a P2P bridge, check if it has a node */ | ||
265 | ppnode = pci_device_to_OF_node(ppdev); | ||
266 | |||
267 | /* Ok, we have found a parent with a device-node, hand over to | ||
268 | * the OF parsing code. | ||
269 | * We build a unit address from the linux device to be used for | ||
270 | * resolution. Note that we use the linux bus number which may | ||
271 | * not match your firmware bus numbering. | ||
272 | * Fortunately, in most cases, interrupt-map-mask doesn't | ||
273 | * include the bus number as part of the matching. | ||
274 | * You should still be careful about that though if you intend | ||
275 | * to rely on this function (you ship a firmware that doesn't | ||
276 | * create device nodes for all PCI devices). | ||
277 | */ | ||
278 | if (ppnode) | ||
279 | break; | ||
280 | |||
281 | /* We can only get here if we hit a P2P bridge with no node, | ||
282 | * let's do standard swizzling and try again | ||
283 | */ | ||
284 | lspec = of_irq_pci_swizzle(PCI_SLOT(pdev->devfn), lspec); | ||
285 | pdev = ppdev; | ||
286 | } | ||
287 | |||
288 | laddr[0] = (pdev->bus->number << 16) | ||
289 | | (pdev->devfn << 8); | ||
290 | laddr[1] = laddr[2] = 0; | ||
291 | return of_irq_map_raw(ppnode, &lspec, 1, laddr, out_irq); | ||
292 | } | ||
293 | EXPORT_SYMBOL_GPL(of_irq_map_pci); | ||
294 | #endif /* CONFIG_PCI */ | ||
295 | |||
296 | /* | ||
297 | * ISA bus specific translator | ||
298 | */ | ||
299 | |||
300 | static int of_bus_isa_match(struct device_node *np) | ||
301 | { | ||
302 | return !strcmp(np->name, "isa"); | ||
303 | } | ||
304 | |||
305 | static void of_bus_isa_count_cells(struct device_node *child, | ||
306 | int *addrc, int *sizec) | ||
307 | { | ||
308 | if (addrc) | ||
309 | *addrc = 2; | ||
310 | if (sizec) | ||
311 | *sizec = 1; | ||
312 | } | ||
313 | |||
314 | static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna) | ||
315 | { | ||
316 | u64 cp, s, da; | ||
317 | |||
318 | /* Check address type match */ | ||
319 | if ((addr[0] ^ range[0]) & 0x00000001) | ||
320 | return OF_BAD_ADDR; | ||
321 | |||
322 | /* Read address values, skipping high cell */ | ||
323 | cp = of_read_number(range + 1, na - 1); | ||
324 | s = of_read_number(range + na + pna, ns); | ||
325 | da = of_read_number(addr + 1, na - 1); | ||
326 | |||
327 | pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da); | ||
328 | |||
329 | if (da < cp || da >= (cp + s)) | ||
330 | return OF_BAD_ADDR; | ||
331 | return da - cp; | ||
332 | } | ||
333 | |||
334 | static int of_bus_isa_translate(u32 *addr, u64 offset, int na) | ||
335 | { | ||
336 | return of_bus_default_translate(addr + 1, offset, na - 1); | ||
337 | } | ||
338 | |||
339 | static unsigned int of_bus_isa_get_flags(const u32 *addr) | ||
340 | { | ||
341 | unsigned int flags = 0; | ||
342 | u32 w = addr[0]; | ||
343 | |||
344 | if (w & 1) | ||
345 | flags |= IORESOURCE_IO; | ||
346 | else | ||
347 | flags |= IORESOURCE_MEM; | ||
348 | return flags; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Array of bus specific translators | ||
353 | */ | ||
354 | |||
355 | static struct of_bus of_busses[] = { | ||
356 | #ifdef CONFIG_PCI | ||
357 | /* PCI */ | ||
358 | { | ||
359 | .name = "pci", | ||
360 | .addresses = "assigned-addresses", | ||
361 | .match = of_bus_pci_match, | ||
362 | .count_cells = of_bus_pci_count_cells, | ||
363 | .map = of_bus_pci_map, | ||
364 | .translate = of_bus_pci_translate, | ||
365 | .get_flags = of_bus_pci_get_flags, | ||
366 | }, | ||
367 | #endif /* CONFIG_PCI */ | ||
368 | /* ISA */ | ||
369 | { | ||
370 | .name = "isa", | ||
371 | .addresses = "reg", | ||
372 | .match = of_bus_isa_match, | ||
373 | .count_cells = of_bus_isa_count_cells, | ||
374 | .map = of_bus_isa_map, | ||
375 | .translate = of_bus_isa_translate, | ||
376 | .get_flags = of_bus_isa_get_flags, | ||
377 | }, | ||
378 | /* Default */ | ||
379 | { | ||
380 | .name = "default", | ||
381 | .addresses = "reg", | ||
382 | .match = NULL, | ||
383 | .count_cells = of_bus_default_count_cells, | ||
384 | .map = of_bus_default_map, | ||
385 | .translate = of_bus_default_translate, | ||
386 | .get_flags = of_bus_default_get_flags, | ||
387 | }, | ||
388 | }; | ||
389 | |||
390 | static struct of_bus *of_match_bus(struct device_node *np) | ||
391 | { | ||
392 | int i; | ||
393 | |||
394 | for (i = 0; i < ARRAY_SIZE(of_busses); i++) | ||
395 | if (!of_busses[i].match || of_busses[i].match(np)) | ||
396 | return &of_busses[i]; | ||
397 | BUG(); | ||
398 | return NULL; | ||
399 | } | ||
400 | |||
401 | static int of_translate_one(struct device_node *parent, struct of_bus *bus, | ||
402 | struct of_bus *pbus, u32 *addr, | ||
403 | int na, int ns, int pna) | ||
404 | { | ||
405 | const u32 *ranges; | ||
406 | unsigned int rlen; | ||
407 | int rone; | ||
408 | u64 offset = OF_BAD_ADDR; | ||
409 | |||
410 | /* Normally, an absence of a "ranges" property means we are | ||
411 | * crossing a non-translatable boundary, and thus the addresses | ||
412 | * below the current not cannot be converted to CPU physical ones. | ||
413 | * Unfortunately, while this is very clear in the spec, it's not | ||
414 | * what Apple understood, and they do have things like /uni-n or | ||
415 | * /ht nodes with no "ranges" property and a lot of perfectly | ||
416 | * useable mapped devices below them. Thus we treat the absence of | ||
417 | * "ranges" as equivalent to an empty "ranges" property which means | ||
418 | * a 1:1 translation at that level. It's up to the caller not to try | ||
419 | * to translate addresses that aren't supposed to be translated in | ||
420 | * the first place. --BenH. | ||
421 | */ | ||
422 | ranges = of_get_property(parent, "ranges", (int *) &rlen); | ||
423 | if (ranges == NULL || rlen == 0) { | ||
424 | offset = of_read_number(addr, na); | ||
425 | memset(addr, 0, pna * 4); | ||
426 | pr_debug("OF: no ranges, 1:1 translation\n"); | ||
427 | goto finish; | ||
428 | } | ||
429 | |||
430 | pr_debug("OF: walking ranges...\n"); | ||
431 | |||
432 | /* Now walk through the ranges */ | ||
433 | rlen /= 4; | ||
434 | rone = na + pna + ns; | ||
435 | for (; rlen >= rone; rlen -= rone, ranges += rone) { | ||
436 | offset = bus->map(addr, ranges, na, ns, pna); | ||
437 | if (offset != OF_BAD_ADDR) | ||
438 | break; | ||
439 | } | ||
440 | if (offset == OF_BAD_ADDR) { | ||
441 | pr_debug("OF: not found !\n"); | ||
442 | return 1; | ||
443 | } | ||
444 | memcpy(addr, ranges + na, 4 * pna); | ||
445 | |||
446 | finish: | ||
447 | of_dump_addr("OF: parent translation for:", addr, pna); | ||
448 | pr_debug("OF: with offset: "PRu64"\n", offset); | ||
449 | |||
450 | /* Translate it into parent bus space */ | ||
451 | return pbus->translate(addr, offset, pna); | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * Translate an address from the device-tree into a CPU physical address, | ||
456 | * this walks up the tree and applies the various bus mappings on the | ||
457 | * way. | ||
458 | * | ||
459 | * Note: We consider that crossing any level with #size-cells == 0 to mean | ||
460 | * that translation is impossible (that is we are not dealing with a value | ||
461 | * that can be mapped to a cpu physical address). This is not really specified | ||
462 | * that way, but this is traditionally the way IBM at least do things | ||
463 | */ | ||
464 | u64 of_translate_address(struct device_node *dev, const u32 *in_addr) | ||
465 | { | ||
466 | struct device_node *parent = NULL; | ||
467 | struct of_bus *bus, *pbus; | ||
468 | u32 addr[OF_MAX_ADDR_CELLS]; | ||
469 | int na, ns, pna, pns; | ||
470 | u64 result = OF_BAD_ADDR; | ||
471 | |||
472 | pr_debug("OF: ** translation for device %s **\n", dev->full_name); | ||
473 | |||
474 | /* Increase refcount at current level */ | ||
475 | of_node_get(dev); | ||
476 | |||
477 | /* Get parent & match bus type */ | ||
478 | parent = of_get_parent(dev); | ||
479 | if (parent == NULL) | ||
480 | goto bail; | ||
481 | bus = of_match_bus(parent); | ||
482 | |||
483 | /* Cound address cells & copy address locally */ | ||
484 | bus->count_cells(dev, &na, &ns); | ||
485 | if (!OF_CHECK_COUNTS(na, ns)) { | ||
486 | printk(KERN_ERR "prom_parse: Bad cell count for %s\n", | ||
487 | dev->full_name); | ||
488 | goto bail; | ||
489 | } | ||
490 | memcpy(addr, in_addr, na * 4); | ||
491 | |||
492 | pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", | ||
493 | bus->name, na, ns, parent->full_name); | ||
494 | of_dump_addr("OF: translating address:", addr, na); | ||
495 | |||
496 | /* Translate */ | ||
497 | for (;;) { | ||
498 | /* Switch to parent bus */ | ||
499 | of_node_put(dev); | ||
500 | dev = parent; | ||
501 | parent = of_get_parent(dev); | ||
502 | |||
503 | /* If root, we have finished */ | ||
504 | if (parent == NULL) { | ||
505 | pr_debug("OF: reached root node\n"); | ||
506 | result = of_read_number(addr, na); | ||
507 | break; | ||
508 | } | ||
509 | |||
510 | /* Get new parent bus and counts */ | ||
511 | pbus = of_match_bus(parent); | ||
512 | pbus->count_cells(dev, &pna, &pns); | ||
513 | if (!OF_CHECK_COUNTS(pna, pns)) { | ||
514 | printk(KERN_ERR "prom_parse: Bad cell count for %s\n", | ||
515 | dev->full_name); | ||
516 | break; | ||
517 | } | ||
518 | |||
519 | pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", | ||
520 | pbus->name, pna, pns, parent->full_name); | ||
521 | |||
522 | /* Apply bus translation */ | ||
523 | if (of_translate_one(dev, bus, pbus, addr, na, ns, pna)) | ||
524 | break; | ||
525 | |||
526 | /* Complete the move up one level */ | ||
527 | na = pna; | ||
528 | ns = pns; | ||
529 | bus = pbus; | ||
530 | |||
531 | of_dump_addr("OF: one level translation:", addr, na); | ||
532 | } | ||
533 | bail: | ||
534 | of_node_put(parent); | ||
535 | of_node_put(dev); | ||
536 | |||
537 | return result; | ||
538 | } | ||
539 | EXPORT_SYMBOL(of_translate_address); | ||
540 | |||
541 | const u32 *of_get_address(struct device_node *dev, int index, u64 *size, | ||
542 | unsigned int *flags) | ||
543 | { | ||
544 | const u32 *prop; | ||
545 | unsigned int psize; | ||
546 | struct device_node *parent; | ||
547 | struct of_bus *bus; | ||
548 | int onesize, i, na, ns; | ||
549 | |||
550 | /* Get parent & match bus type */ | ||
551 | parent = of_get_parent(dev); | ||
552 | if (parent == NULL) | ||
553 | return NULL; | ||
554 | bus = of_match_bus(parent); | ||
555 | bus->count_cells(dev, &na, &ns); | ||
556 | of_node_put(parent); | ||
557 | if (!OF_CHECK_COUNTS(na, ns)) | ||
558 | return NULL; | ||
559 | |||
560 | /* Get "reg" or "assigned-addresses" property */ | ||
561 | prop = of_get_property(dev, bus->addresses, (int *) &psize); | ||
562 | if (prop == NULL) | ||
563 | return NULL; | ||
564 | psize /= 4; | ||
565 | |||
566 | onesize = na + ns; | ||
567 | for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) | ||
568 | if (i == index) { | ||
569 | if (size) | ||
570 | *size = of_read_number(prop + na, ns); | ||
571 | if (flags) | ||
572 | *flags = bus->get_flags(prop); | ||
573 | return prop; | ||
574 | } | ||
575 | return NULL; | ||
576 | } | ||
577 | EXPORT_SYMBOL(of_get_address); | ||
578 | |||
579 | static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, | ||
580 | u64 size, unsigned int flags, | ||
581 | struct resource *r) | ||
582 | { | ||
583 | u64 taddr; | ||
584 | |||
585 | if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) | ||
586 | return -EINVAL; | ||
587 | taddr = of_translate_address(dev, addrp); | ||
588 | if (taddr == OF_BAD_ADDR) | ||
589 | return -EINVAL; | ||
590 | memset(r, 0, sizeof(struct resource)); | ||
591 | if (flags & IORESOURCE_IO) { | ||
592 | unsigned long port; | ||
593 | port = -1; /* pci_address_to_pio(taddr); */ | ||
594 | if (port == (unsigned long)-1) | ||
595 | return -EINVAL; | ||
596 | r->start = port; | ||
597 | r->end = port + size - 1; | ||
598 | } else { | ||
599 | r->start = taddr; | ||
600 | r->end = taddr + size - 1; | ||
601 | } | ||
602 | r->flags = flags; | ||
603 | r->name = dev->name; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | int of_address_to_resource(struct device_node *dev, int index, | ||
608 | struct resource *r) | ||
609 | { | ||
610 | const u32 *addrp; | ||
611 | u64 size; | ||
612 | unsigned int flags; | ||
613 | |||
614 | addrp = of_get_address(dev, index, &size, &flags); | ||
615 | if (addrp == NULL) | ||
616 | return -EINVAL; | ||
617 | return __of_address_to_resource(dev, addrp, size, flags, r); | ||
618 | } | ||
619 | EXPORT_SYMBOL_GPL(of_address_to_resource); | ||
620 | |||
621 | void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop, | ||
622 | unsigned long *busno, unsigned long *phys, unsigned long *size) | ||
623 | { | ||
624 | const u32 *dma_window; | ||
625 | u32 cells; | ||
626 | const unsigned char *prop; | ||
627 | |||
628 | dma_window = dma_window_prop; | ||
629 | |||
630 | /* busno is always one cell */ | ||
631 | *busno = *(dma_window++); | ||
632 | |||
633 | prop = of_get_property(dn, "ibm,#dma-address-cells", NULL); | ||
634 | if (!prop) | ||
635 | prop = of_get_property(dn, "#address-cells", NULL); | ||
636 | |||
637 | cells = prop ? *(u32 *)prop : of_n_addr_cells(dn); | ||
638 | *phys = of_read_number(dma_window, cells); | ||
639 | |||
640 | dma_window += cells; | ||
641 | |||
642 | prop = of_get_property(dn, "ibm,#dma-size-cells", NULL); | ||
643 | cells = prop ? *(u32 *)prop : of_n_size_cells(dn); | ||
644 | *size = of_read_number(dma_window, cells); | ||
645 | } | ||
646 | |||
647 | /* | ||
648 | * Interrupt remapper | ||
649 | */ | ||
650 | |||
651 | static unsigned int of_irq_workarounds; | ||
652 | static struct device_node *of_irq_dflt_pic; | ||
653 | |||
654 | static struct device_node *of_irq_find_parent(struct device_node *child) | ||
655 | { | ||
656 | struct device_node *p; | ||
657 | const phandle *parp; | ||
658 | |||
659 | if (!of_node_get(child)) | ||
660 | return NULL; | ||
661 | |||
662 | do { | ||
663 | parp = of_get_property(child, "interrupt-parent", NULL); | ||
664 | if (parp == NULL) | ||
665 | p = of_get_parent(child); | ||
666 | else { | ||
667 | if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) | ||
668 | p = of_node_get(of_irq_dflt_pic); | ||
669 | else | ||
670 | p = of_find_node_by_phandle(*parp); | ||
671 | } | ||
672 | of_node_put(child); | ||
673 | child = p; | ||
674 | } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); | ||
675 | |||
676 | return p; | ||
677 | } | ||
678 | |||
679 | /* This doesn't need to be called if you don't have any special workaround | ||
680 | * flags to pass | ||
681 | */ | ||
682 | void of_irq_map_init(unsigned int flags) | ||
683 | { | ||
684 | of_irq_workarounds = flags; | ||
685 | |||
686 | /* OldWorld, don't bother looking at other things */ | ||
687 | if (flags & OF_IMAP_OLDWORLD_MAC) | ||
688 | return; | ||
689 | |||
690 | /* If we don't have phandles, let's try to locate a default interrupt | ||
691 | * controller (happens when booting with BootX). We do a first match | ||
692 | * here, hopefully, that only ever happens on machines with one | ||
693 | * controller. | ||
694 | */ | ||
695 | if (flags & OF_IMAP_NO_PHANDLE) { | ||
696 | struct device_node *np; | ||
697 | |||
698 | for (np = NULL; (np = of_find_all_nodes(np)) != NULL;) { | ||
699 | if (of_get_property(np, "interrupt-controller", NULL) | ||
700 | == NULL) | ||
701 | continue; | ||
702 | /* Skip /chosen/interrupt-controller */ | ||
703 | if (strcmp(np->name, "chosen") == 0) | ||
704 | continue; | ||
705 | /* It seems like at least one person on this planet | ||
706 | * wants to use BootX on a machine with an AppleKiwi | ||
707 | * controller which happens to pretend to be an | ||
708 | * interrupt controller too. | ||
709 | */ | ||
710 | if (strcmp(np->name, "AppleKiwi") == 0) | ||
711 | continue; | ||
712 | /* I think we found one ! */ | ||
713 | of_irq_dflt_pic = np; | ||
714 | break; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | } | ||
719 | |||
720 | int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize, | ||
721 | const u32 *addr, struct of_irq *out_irq) | ||
722 | { | ||
723 | struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; | ||
724 | const u32 *tmp, *imap, *imask; | ||
725 | u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; | ||
726 | int imaplen, match, i; | ||
727 | |||
728 | pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...]," | ||
729 | "ointsize=%d\n", | ||
730 | parent->full_name, intspec[0], intspec[1], ointsize); | ||
731 | |||
732 | ipar = of_node_get(parent); | ||
733 | |||
734 | /* First get the #interrupt-cells property of the current cursor | ||
735 | * that tells us how to interpret the passed-in intspec. If there | ||
736 | * is none, we are nice and just walk up the tree | ||
737 | */ | ||
738 | do { | ||
739 | tmp = of_get_property(ipar, "#interrupt-cells", NULL); | ||
740 | if (tmp != NULL) { | ||
741 | intsize = *tmp; | ||
742 | break; | ||
743 | } | ||
744 | tnode = ipar; | ||
745 | ipar = of_irq_find_parent(ipar); | ||
746 | of_node_put(tnode); | ||
747 | } while (ipar); | ||
748 | if (ipar == NULL) { | ||
749 | pr_debug(" -> no parent found !\n"); | ||
750 | goto fail; | ||
751 | } | ||
752 | |||
753 | pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", | ||
754 | ipar->full_name, intsize); | ||
755 | |||
756 | if (ointsize != intsize) | ||
757 | return -EINVAL; | ||
758 | |||
759 | /* Look for this #address-cells. We have to implement the old linux | ||
760 | * trick of looking for the parent here as some device-trees rely on it | ||
761 | */ | ||
762 | old = of_node_get(ipar); | ||
763 | do { | ||
764 | tmp = of_get_property(old, "#address-cells", NULL); | ||
765 | tnode = of_get_parent(old); | ||
766 | of_node_put(old); | ||
767 | old = tnode; | ||
768 | } while (old && tmp == NULL); | ||
769 | of_node_put(old); | ||
770 | old = NULL; | ||
771 | addrsize = (tmp == NULL) ? 2 : *tmp; | ||
772 | |||
773 | pr_debug(" -> addrsize=%d\n", addrsize); | ||
774 | |||
775 | /* Now start the actual "proper" walk of the interrupt tree */ | ||
776 | while (ipar != NULL) { | ||
777 | /* Now check if cursor is an interrupt-controller and if it is | ||
778 | * then we are done | ||
779 | */ | ||
780 | if (of_get_property(ipar, "interrupt-controller", NULL) != | ||
781 | NULL) { | ||
782 | pr_debug(" -> got it !\n"); | ||
783 | memcpy(out_irq->specifier, intspec, | ||
784 | intsize * sizeof(u32)); | ||
785 | out_irq->size = intsize; | ||
786 | out_irq->controller = ipar; | ||
787 | of_node_put(old); | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | /* Now look for an interrupt-map */ | ||
792 | imap = of_get_property(ipar, "interrupt-map", &imaplen); | ||
793 | /* No interrupt map, check for an interrupt parent */ | ||
794 | if (imap == NULL) { | ||
795 | pr_debug(" -> no map, getting parent\n"); | ||
796 | newpar = of_irq_find_parent(ipar); | ||
797 | goto skiplevel; | ||
798 | } | ||
799 | imaplen /= sizeof(u32); | ||
800 | |||
801 | /* Look for a mask */ | ||
802 | imask = of_get_property(ipar, "interrupt-map-mask", NULL); | ||
803 | |||
804 | /* If we were passed no "reg" property and we attempt to parse | ||
805 | * an interrupt-map, then #address-cells must be 0. | ||
806 | * Fail if it's not. | ||
807 | */ | ||
808 | if (addr == NULL && addrsize != 0) { | ||
809 | pr_debug(" -> no reg passed in when needed !\n"); | ||
810 | goto fail; | ||
811 | } | ||
812 | |||
813 | /* Parse interrupt-map */ | ||
814 | match = 0; | ||
815 | while (imaplen > (addrsize + intsize + 1) && !match) { | ||
816 | /* Compare specifiers */ | ||
817 | match = 1; | ||
818 | for (i = 0; i < addrsize && match; ++i) { | ||
819 | u32 mask = imask ? imask[i] : 0xffffffffu; | ||
820 | match = ((addr[i] ^ imap[i]) & mask) == 0; | ||
821 | } | ||
822 | for (; i < (addrsize + intsize) && match; ++i) { | ||
823 | u32 mask = imask ? imask[i] : 0xffffffffu; | ||
824 | match = | ||
825 | ((intspec[i-addrsize] ^ imap[i]) | ||
826 | & mask) == 0; | ||
827 | } | ||
828 | imap += addrsize + intsize; | ||
829 | imaplen -= addrsize + intsize; | ||
830 | |||
831 | pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); | ||
832 | |||
833 | /* Get the interrupt parent */ | ||
834 | if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) | ||
835 | newpar = of_node_get(of_irq_dflt_pic); | ||
836 | else | ||
837 | newpar = | ||
838 | of_find_node_by_phandle((phandle)*imap); | ||
839 | imap++; | ||
840 | --imaplen; | ||
841 | |||
842 | /* Check if not found */ | ||
843 | if (newpar == NULL) { | ||
844 | pr_debug(" -> imap parent not found !\n"); | ||
845 | goto fail; | ||
846 | } | ||
847 | |||
848 | /* Get #interrupt-cells and #address-cells of new | ||
849 | * parent | ||
850 | */ | ||
851 | tmp = of_get_property(newpar, "#interrupt-cells", NULL); | ||
852 | if (tmp == NULL) { | ||
853 | pr_debug(" -> parent lacks " | ||
854 | "#interrupt-cells!\n"); | ||
855 | goto fail; | ||
856 | } | ||
857 | newintsize = *tmp; | ||
858 | tmp = of_get_property(newpar, "#address-cells", NULL); | ||
859 | newaddrsize = (tmp == NULL) ? 0 : *tmp; | ||
860 | |||
861 | pr_debug(" -> newintsize=%d, newaddrsize=%d\n", | ||
862 | newintsize, newaddrsize); | ||
863 | |||
864 | /* Check for malformed properties */ | ||
865 | if (imaplen < (newaddrsize + newintsize)) | ||
866 | goto fail; | ||
867 | |||
868 | imap += newaddrsize + newintsize; | ||
869 | imaplen -= newaddrsize + newintsize; | ||
870 | |||
871 | pr_debug(" -> imaplen=%d\n", imaplen); | ||
872 | } | ||
873 | if (!match) | ||
874 | goto fail; | ||
875 | |||
876 | of_node_put(old); | ||
877 | old = of_node_get(newpar); | ||
878 | addrsize = newaddrsize; | ||
879 | intsize = newintsize; | ||
880 | intspec = imap - intsize; | ||
881 | addr = intspec - addrsize; | ||
882 | |||
883 | skiplevel: | ||
884 | /* Iterate again with new parent */ | ||
885 | pr_debug(" -> new parent: %s\n", | ||
886 | newpar ? newpar->full_name : "<>"); | ||
887 | of_node_put(ipar); | ||
888 | ipar = newpar; | ||
889 | newpar = NULL; | ||
890 | } | ||
891 | fail: | ||
892 | of_node_put(ipar); | ||
893 | of_node_put(old); | ||
894 | of_node_put(newpar); | ||
895 | |||
896 | return -EINVAL; | ||
897 | } | ||
898 | EXPORT_SYMBOL_GPL(of_irq_map_raw); | ||
899 | |||
900 | int of_irq_map_one(struct device_node *device, | ||
901 | int index, struct of_irq *out_irq) | ||
902 | { | ||
903 | struct device_node *p; | ||
904 | const u32 *intspec, *tmp, *addr; | ||
905 | u32 intsize, intlen; | ||
906 | int res; | ||
907 | |||
908 | pr_debug("of_irq_map_one: dev=%s, index=%d\n", | ||
909 | device->full_name, index); | ||
910 | |||
911 | /* Get the interrupts property */ | ||
912 | intspec = of_get_property(device, "interrupts", (int *) &intlen); | ||
913 | if (intspec == NULL) | ||
914 | return -EINVAL; | ||
915 | intlen /= sizeof(u32); | ||
916 | |||
917 | pr_debug(" intspec=%d intlen=%d\n", *intspec, intlen); | ||
918 | |||
919 | /* Get the reg property (if any) */ | ||
920 | addr = of_get_property(device, "reg", NULL); | ||
921 | |||
922 | /* Look for the interrupt parent. */ | ||
923 | p = of_irq_find_parent(device); | ||
924 | if (p == NULL) | ||
925 | return -EINVAL; | ||
926 | |||
927 | /* Get size of interrupt specifier */ | ||
928 | tmp = of_get_property(p, "#interrupt-cells", NULL); | ||
929 | if (tmp == NULL) { | ||
930 | of_node_put(p); | ||
931 | return -EINVAL; | ||
932 | } | ||
933 | intsize = *tmp; | ||
934 | |||
935 | pr_debug(" intsize=%d intlen=%d\n", intsize, intlen); | ||
936 | |||
937 | /* Check index */ | ||
938 | if ((index + 1) * intsize > intlen) | ||
939 | return -EINVAL; | ||
940 | |||
941 | /* Get new specifier and map it */ | ||
942 | res = of_irq_map_raw(p, intspec + index * intsize, intsize, | ||
943 | addr, out_irq); | ||
944 | of_node_put(p); | ||
945 | return res; | ||
946 | } | ||
947 | EXPORT_SYMBOL_GPL(of_irq_map_one); | ||
948 | |||
949 | /** | ||
950 | * Search the device tree for the best MAC address to use. 'mac-address' is | ||
951 | * checked first, because that is supposed to contain to "most recent" MAC | ||
952 | * address. If that isn't set, then 'local-mac-address' is checked next, | ||
953 | * because that is the default address. If that isn't set, then the obsolete | ||
954 | * 'address' is checked, just in case we're using an old device tree. | ||
955 | * | ||
956 | * Note that the 'address' property is supposed to contain a virtual address of | ||
957 | * the register set, but some DTS files have redefined that property to be the | ||
958 | * MAC address. | ||
959 | * | ||
960 | * All-zero MAC addresses are rejected, because those could be properties that | ||
961 | * exist in the device tree, but were not set by U-Boot. For example, the | ||
962 | * DTS could define 'mac-address' and 'local-mac-address', with zero MAC | ||
963 | * addresses. Some older U-Boots only initialized 'local-mac-address'. In | ||
964 | * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists | ||
965 | * but is all zeros. | ||
966 | */ | ||
967 | const void *of_get_mac_address(struct device_node *np) | ||
968 | { | ||
969 | struct property *pp; | ||
970 | |||
971 | pp = of_find_property(np, "mac-address", NULL); | ||
972 | if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) | ||
973 | return pp->value; | ||
974 | |||
975 | pp = of_find_property(np, "local-mac-address", NULL); | ||
976 | if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) | ||
977 | return pp->value; | ||
978 | |||
979 | pp = of_find_property(np, "address", NULL); | ||
980 | if (pp && (pp->length == 6) && is_valid_ether_addr(pp->value)) | ||
981 | return pp->value; | ||
982 | |||
983 | return NULL; | ||
984 | } | ||
985 | EXPORT_SYMBOL(of_get_mac_address); | ||
986 | |||
987 | int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) | ||
988 | { | ||
989 | struct of_irq out_irq; | ||
990 | int irq; | ||
991 | int res; | ||
992 | |||
993 | res = of_irq_map_one(dev, index, &out_irq); | ||
994 | |||
995 | /* Get irq for the device */ | ||
996 | if (res) { | ||
997 | pr_debug("IRQ not found... code = %d", res); | ||
998 | return NO_IRQ; | ||
999 | } | ||
1000 | /* Assuming single interrupt controller... */ | ||
1001 | irq = out_irq.specifier[0]; | ||
1002 | |||
1003 | pr_debug("IRQ found = %d", irq); | ||
1004 | |||
1005 | /* Only dereference the resource if both the | ||
1006 | * resource and the irq are valid. */ | ||
1007 | if (r && irq != NO_IRQ) { | ||
1008 | r->start = r->end = irq; | ||
1009 | r->flags = IORESOURCE_IRQ; | ||
1010 | } | ||
1011 | |||
1012 | return irq; | ||
1013 | } | ||
1014 | EXPORT_SYMBOL_GPL(of_irq_to_resource); | ||
1015 | |||
1016 | void __iomem *of_iomap(struct device_node *np, int index) | ||
1017 | { | ||
1018 | struct resource res; | ||
1019 | |||
1020 | if (of_address_to_resource(np, index, &res)) | ||
1021 | return NULL; | ||
1022 | |||
1023 | return ioremap(res.start, 1 + res.end - res.start); | ||
1024 | } | ||
1025 | EXPORT_SYMBOL(of_iomap); | ||