1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * FDT Address translation based on u-boot fdt_support.c which in turn was
4*4882a593Smuzhiyun * based on the kernel unflattened DT address translation code.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * (C) Copyright 2007
7*4882a593Smuzhiyun * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Copyright 2010-2011 Freescale Semiconductor, Inc.
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #define pr_fmt(fmt) "OF: fdt: " fmt
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/libfdt.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/of_fdt.h>
18*4882a593Smuzhiyun #include <linux/sizes.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun /* Max address size we deal with */
21*4882a593Smuzhiyun #define OF_MAX_ADDR_CELLS 4
22*4882a593Smuzhiyun #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
23*4882a593Smuzhiyun (ns) > 0)
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* Debug utility */
26*4882a593Smuzhiyun #ifdef DEBUG
of_dump_addr(const char * s,const __be32 * addr,int na)27*4882a593Smuzhiyun static void __init of_dump_addr(const char *s, const __be32 *addr, int na)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun pr_debug("%s", s);
30*4882a593Smuzhiyun while(na--)
31*4882a593Smuzhiyun pr_cont(" %08x", *(addr++));
32*4882a593Smuzhiyun pr_cont("\n");
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun #else
of_dump_addr(const char * s,const __be32 * addr,int na)35*4882a593Smuzhiyun static void __init of_dump_addr(const char *s, const __be32 *addr, int na) { }
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* Callbacks for bus specific translators */
39*4882a593Smuzhiyun struct of_bus {
40*4882a593Smuzhiyun void (*count_cells)(const void *blob, int parentoffset,
41*4882a593Smuzhiyun int *addrc, int *sizec);
42*4882a593Smuzhiyun u64 (*map)(__be32 *addr, const __be32 *range,
43*4882a593Smuzhiyun int na, int ns, int pna);
44*4882a593Smuzhiyun int (*translate)(__be32 *addr, u64 offset, int na);
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Default translator (generic bus) */
fdt_bus_default_count_cells(const void * blob,int parentoffset,int * addrc,int * sizec)48*4882a593Smuzhiyun static void __init fdt_bus_default_count_cells(const void *blob, int parentoffset,
49*4882a593Smuzhiyun int *addrc, int *sizec)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun const __be32 *prop;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun if (addrc) {
54*4882a593Smuzhiyun prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
55*4882a593Smuzhiyun if (prop)
56*4882a593Smuzhiyun *addrc = be32_to_cpup(prop);
57*4882a593Smuzhiyun else
58*4882a593Smuzhiyun *addrc = dt_root_addr_cells;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (sizec) {
62*4882a593Smuzhiyun prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
63*4882a593Smuzhiyun if (prop)
64*4882a593Smuzhiyun *sizec = be32_to_cpup(prop);
65*4882a593Smuzhiyun else
66*4882a593Smuzhiyun *sizec = dt_root_size_cells;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
fdt_bus_default_map(__be32 * addr,const __be32 * range,int na,int ns,int pna)70*4882a593Smuzhiyun static u64 __init fdt_bus_default_map(__be32 *addr, const __be32 *range,
71*4882a593Smuzhiyun int na, int ns, int pna)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun u64 cp, s, da;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun cp = of_read_number(range, na);
76*4882a593Smuzhiyun s = of_read_number(range + na + pna, ns);
77*4882a593Smuzhiyun da = of_read_number(addr, na);
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun pr_debug("default map, cp=%llx, s=%llx, da=%llx\n",
80*4882a593Smuzhiyun cp, s, da);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun if (da < cp || da >= (cp + s))
83*4882a593Smuzhiyun return OF_BAD_ADDR;
84*4882a593Smuzhiyun return da - cp;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
fdt_bus_default_translate(__be32 * addr,u64 offset,int na)87*4882a593Smuzhiyun static int __init fdt_bus_default_translate(__be32 *addr, u64 offset, int na)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun u64 a = of_read_number(addr, na);
90*4882a593Smuzhiyun memset(addr, 0, na * 4);
91*4882a593Smuzhiyun a += offset;
92*4882a593Smuzhiyun if (na > 1)
93*4882a593Smuzhiyun addr[na - 2] = cpu_to_fdt32(a >> 32);
94*4882a593Smuzhiyun addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return 0;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun /* Array of bus specific translators */
100*4882a593Smuzhiyun static const struct of_bus of_busses[] __initconst = {
101*4882a593Smuzhiyun /* Default */
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun .count_cells = fdt_bus_default_count_cells,
104*4882a593Smuzhiyun .map = fdt_bus_default_map,
105*4882a593Smuzhiyun .translate = fdt_bus_default_translate,
106*4882a593Smuzhiyun },
107*4882a593Smuzhiyun };
108*4882a593Smuzhiyun
fdt_translate_one(const void * blob,int parent,const struct of_bus * bus,const struct of_bus * pbus,__be32 * addr,int na,int ns,int pna,const char * rprop)109*4882a593Smuzhiyun static int __init fdt_translate_one(const void *blob, int parent,
110*4882a593Smuzhiyun const struct of_bus *bus,
111*4882a593Smuzhiyun const struct of_bus *pbus, __be32 *addr,
112*4882a593Smuzhiyun int na, int ns, int pna, const char *rprop)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun const __be32 *ranges;
115*4882a593Smuzhiyun int rlen;
116*4882a593Smuzhiyun int rone;
117*4882a593Smuzhiyun u64 offset = OF_BAD_ADDR;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun ranges = fdt_getprop(blob, parent, rprop, &rlen);
120*4882a593Smuzhiyun if (!ranges)
121*4882a593Smuzhiyun return 1;
122*4882a593Smuzhiyun if (rlen == 0) {
123*4882a593Smuzhiyun offset = of_read_number(addr, na);
124*4882a593Smuzhiyun memset(addr, 0, pna * 4);
125*4882a593Smuzhiyun pr_debug("empty ranges, 1:1 translation\n");
126*4882a593Smuzhiyun goto finish;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun pr_debug("walking ranges...\n");
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Now walk through the ranges */
132*4882a593Smuzhiyun rlen /= 4;
133*4882a593Smuzhiyun rone = na + pna + ns;
134*4882a593Smuzhiyun for (; rlen >= rone; rlen -= rone, ranges += rone) {
135*4882a593Smuzhiyun offset = bus->map(addr, ranges, na, ns, pna);
136*4882a593Smuzhiyun if (offset != OF_BAD_ADDR)
137*4882a593Smuzhiyun break;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun if (offset == OF_BAD_ADDR) {
140*4882a593Smuzhiyun pr_debug("not found !\n");
141*4882a593Smuzhiyun return 1;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun memcpy(addr, ranges + na, 4 * pna);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun finish:
146*4882a593Smuzhiyun of_dump_addr("parent translation for:", addr, pna);
147*4882a593Smuzhiyun pr_debug("with offset: %llx\n", offset);
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* Translate it into parent bus space */
150*4882a593Smuzhiyun return pbus->translate(addr, offset, pna);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun * Translate an address from the device-tree into a CPU physical address,
155*4882a593Smuzhiyun * this walks up the tree and applies the various bus mappings on the
156*4882a593Smuzhiyun * way.
157*4882a593Smuzhiyun *
158*4882a593Smuzhiyun * Note: We consider that crossing any level with #size-cells == 0 to mean
159*4882a593Smuzhiyun * that translation is impossible (that is we are not dealing with a value
160*4882a593Smuzhiyun * that can be mapped to a cpu physical address). This is not really specified
161*4882a593Smuzhiyun * that way, but this is traditionally the way IBM at least do things
162*4882a593Smuzhiyun */
fdt_translate_address(const void * blob,int node_offset)163*4882a593Smuzhiyun static u64 __init fdt_translate_address(const void *blob, int node_offset)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun int parent, len;
166*4882a593Smuzhiyun const struct of_bus *bus, *pbus;
167*4882a593Smuzhiyun const __be32 *reg;
168*4882a593Smuzhiyun __be32 addr[OF_MAX_ADDR_CELLS];
169*4882a593Smuzhiyun int na, ns, pna, pns;
170*4882a593Smuzhiyun u64 result = OF_BAD_ADDR;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun pr_debug("** translation for device %s **\n",
173*4882a593Smuzhiyun fdt_get_name(blob, node_offset, NULL));
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun reg = fdt_getprop(blob, node_offset, "reg", &len);
176*4882a593Smuzhiyun if (!reg) {
177*4882a593Smuzhiyun pr_err("warning: device tree node '%s' has no address.\n",
178*4882a593Smuzhiyun fdt_get_name(blob, node_offset, NULL));
179*4882a593Smuzhiyun goto bail;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Get parent & match bus type */
183*4882a593Smuzhiyun parent = fdt_parent_offset(blob, node_offset);
184*4882a593Smuzhiyun if (parent < 0)
185*4882a593Smuzhiyun goto bail;
186*4882a593Smuzhiyun bus = &of_busses[0];
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* Cound address cells & copy address locally */
189*4882a593Smuzhiyun bus->count_cells(blob, parent, &na, &ns);
190*4882a593Smuzhiyun if (!OF_CHECK_COUNTS(na, ns)) {
191*4882a593Smuzhiyun pr_err("Bad cell count for %s\n",
192*4882a593Smuzhiyun fdt_get_name(blob, node_offset, NULL));
193*4882a593Smuzhiyun goto bail;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun memcpy(addr, reg, na * 4);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun pr_debug("bus (na=%d, ns=%d) on %s\n",
198*4882a593Smuzhiyun na, ns, fdt_get_name(blob, parent, NULL));
199*4882a593Smuzhiyun of_dump_addr("translating address:", addr, na);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* Translate */
202*4882a593Smuzhiyun for (;;) {
203*4882a593Smuzhiyun /* Switch to parent bus */
204*4882a593Smuzhiyun node_offset = parent;
205*4882a593Smuzhiyun parent = fdt_parent_offset(blob, node_offset);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun /* If root, we have finished */
208*4882a593Smuzhiyun if (parent < 0) {
209*4882a593Smuzhiyun pr_debug("reached root node\n");
210*4882a593Smuzhiyun result = of_read_number(addr, na);
211*4882a593Smuzhiyun break;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun /* Get new parent bus and counts */
215*4882a593Smuzhiyun pbus = &of_busses[0];
216*4882a593Smuzhiyun pbus->count_cells(blob, parent, &pna, &pns);
217*4882a593Smuzhiyun if (!OF_CHECK_COUNTS(pna, pns)) {
218*4882a593Smuzhiyun pr_err("Bad cell count for %s\n",
219*4882a593Smuzhiyun fdt_get_name(blob, node_offset, NULL));
220*4882a593Smuzhiyun break;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun pr_debug("parent bus (na=%d, ns=%d) on %s\n",
224*4882a593Smuzhiyun pna, pns, fdt_get_name(blob, parent, NULL));
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* Apply bus translation */
227*4882a593Smuzhiyun if (fdt_translate_one(blob, node_offset, bus, pbus,
228*4882a593Smuzhiyun addr, na, ns, pna, "ranges"))
229*4882a593Smuzhiyun break;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun /* Complete the move up one level */
232*4882a593Smuzhiyun na = pna;
233*4882a593Smuzhiyun ns = pns;
234*4882a593Smuzhiyun bus = pbus;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun of_dump_addr("one level translation:", addr, na);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun bail:
239*4882a593Smuzhiyun return result;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /**
243*4882a593Smuzhiyun * of_flat_dt_translate_address - translate DT addr into CPU phys addr
244*4882a593Smuzhiyun * @node: node in the flat blob
245*4882a593Smuzhiyun */
of_flat_dt_translate_address(unsigned long node)246*4882a593Smuzhiyun u64 __init of_flat_dt_translate_address(unsigned long node)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun return fdt_translate_address(initial_boot_params, node);
249*4882a593Smuzhiyun }
250