2 * FDT Address translation based on u-boot fdt_support.c which in turn was
3 * based on the kernel unflattened DT address translation code.
6 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
8 * Copyright 2010-2011 Freescale Semiconductor, Inc.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 #include <linux/kernel.h>
16 #include <linux/libfdt.h>
18 #include <linux/of_fdt.h>
19 #include <linux/sizes.h>
21 /* Max address size we deal with */
22 #define OF_MAX_ADDR_CELLS 4
23 #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
28 static void __init
of_dump_addr(const char *s
, const __be32
*addr
, int na
)
32 pr_cont(" %08x", *(addr
++));
36 static void __init
of_dump_addr(const char *s
, const __be32
*addr
, int na
) { }
39 /* Callbacks for bus specific translators */
41 void (*count_cells
)(const void *blob
, int parentoffset
,
42 int *addrc
, int *sizec
);
43 u64 (*map
)(__be32
*addr
, const __be32
*range
,
44 int na
, int ns
, int pna
);
45 int (*translate
)(__be32
*addr
, u64 offset
, int na
);
48 /* Default translator (generic bus) */
49 static void __init
fdt_bus_default_count_cells(const void *blob
, int parentoffset
,
50 int *addrc
, int *sizec
)
55 prop
= fdt_getprop(blob
, parentoffset
, "#address-cells", NULL
);
57 *addrc
= be32_to_cpup(prop
);
59 *addrc
= dt_root_addr_cells
;
63 prop
= fdt_getprop(blob
, parentoffset
, "#size-cells", NULL
);
65 *sizec
= be32_to_cpup(prop
);
67 *sizec
= dt_root_size_cells
;
71 static u64 __init
fdt_bus_default_map(__be32
*addr
, const __be32
*range
,
72 int na
, int ns
, int pna
)
76 cp
= of_read_number(range
, na
);
77 s
= of_read_number(range
+ na
+ pna
, ns
);
78 da
= of_read_number(addr
, na
);
80 pr_debug("FDT: default map, cp=%llx, s=%llx, da=%llx\n",
83 if (da
< cp
|| da
>= (cp
+ s
))
88 static int __init
fdt_bus_default_translate(__be32
*addr
, u64 offset
, int na
)
90 u64 a
= of_read_number(addr
, na
);
91 memset(addr
, 0, na
* 4);
94 addr
[na
- 2] = cpu_to_fdt32(a
>> 32);
95 addr
[na
- 1] = cpu_to_fdt32(a
& 0xffffffffu
);
100 /* Array of bus specific translators */
101 static const struct of_bus of_busses
[] __initconst
= {
104 .count_cells
= fdt_bus_default_count_cells
,
105 .map
= fdt_bus_default_map
,
106 .translate
= fdt_bus_default_translate
,
110 static int __init
fdt_translate_one(const void *blob
, int parent
,
111 const struct of_bus
*bus
,
112 const struct of_bus
*pbus
, __be32
*addr
,
113 int na
, int ns
, int pna
, const char *rprop
)
115 const __be32
*ranges
;
118 u64 offset
= OF_BAD_ADDR
;
120 ranges
= fdt_getprop(blob
, parent
, rprop
, &rlen
);
124 offset
= of_read_number(addr
, na
);
125 memset(addr
, 0, pna
* 4);
126 pr_debug("FDT: empty ranges, 1:1 translation\n");
130 pr_debug("FDT: walking ranges...\n");
132 /* Now walk through the ranges */
134 rone
= na
+ pna
+ ns
;
135 for (; rlen
>= rone
; rlen
-= rone
, ranges
+= rone
) {
136 offset
= bus
->map(addr
, ranges
, na
, ns
, pna
);
137 if (offset
!= OF_BAD_ADDR
)
140 if (offset
== OF_BAD_ADDR
) {
141 pr_debug("FDT: not found !\n");
144 memcpy(addr
, ranges
+ na
, 4 * pna
);
147 of_dump_addr("FDT: parent translation for:", addr
, pna
);
148 pr_debug("FDT: with offset: %llx\n", offset
);
150 /* Translate it into parent bus space */
151 return pbus
->translate(addr
, offset
, pna
);
155 * Translate an address from the device-tree into a CPU physical address,
156 * this walks up the tree and applies the various bus mappings on the
159 * Note: We consider that crossing any level with #size-cells == 0 to mean
160 * that translation is impossible (that is we are not dealing with a value
161 * that can be mapped to a cpu physical address). This is not really specified
162 * that way, but this is traditionally the way IBM at least do things
164 u64 __init
fdt_translate_address(const void *blob
, int node_offset
)
167 const struct of_bus
*bus
, *pbus
;
169 __be32 addr
[OF_MAX_ADDR_CELLS
];
170 int na
, ns
, pna
, pns
;
171 u64 result
= OF_BAD_ADDR
;
173 pr_debug("FDT: ** translation for device %s **\n",
174 fdt_get_name(blob
, node_offset
, NULL
));
176 reg
= fdt_getprop(blob
, node_offset
, "reg", &len
);
178 pr_err("FDT: warning: device tree node '%s' has no address.\n",
179 fdt_get_name(blob
, node_offset
, NULL
));
183 /* Get parent & match bus type */
184 parent
= fdt_parent_offset(blob
, node_offset
);
189 /* Cound address cells & copy address locally */
190 bus
->count_cells(blob
, parent
, &na
, &ns
);
191 if (!OF_CHECK_COUNTS(na
, ns
)) {
192 pr_err("FDT: Bad cell count for %s\n",
193 fdt_get_name(blob
, node_offset
, NULL
));
196 memcpy(addr
, reg
, na
* 4);
198 pr_debug("FDT: bus (na=%d, ns=%d) on %s\n",
199 na
, ns
, fdt_get_name(blob
, parent
, NULL
));
200 of_dump_addr("OF: translating address:", addr
, na
);
204 /* Switch to parent bus */
205 node_offset
= parent
;
206 parent
= fdt_parent_offset(blob
, node_offset
);
208 /* If root, we have finished */
210 pr_debug("FDT: reached root node\n");
211 result
= of_read_number(addr
, na
);
215 /* Get new parent bus and counts */
216 pbus
= &of_busses
[0];
217 pbus
->count_cells(blob
, parent
, &pna
, &pns
);
218 if (!OF_CHECK_COUNTS(pna
, pns
)) {
219 pr_err("FDT: Bad cell count for %s\n",
220 fdt_get_name(blob
, node_offset
, NULL
));
224 pr_debug("FDT: parent bus (na=%d, ns=%d) on %s\n",
225 pna
, pns
, fdt_get_name(blob
, parent
, NULL
));
227 /* Apply bus translation */
228 if (fdt_translate_one(blob
, node_offset
, bus
, pbus
,
229 addr
, na
, ns
, pna
, "ranges"))
232 /* Complete the move up one level */
237 of_dump_addr("FDT: one level translation:", addr
, na
);