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