// SPDX-License-Identifier: GPL-2.0+ /* * FDT Address translation based on u-boot fdt_support.c which in turn was * based on the kernel unflattened DT address translation code. * * (C) Copyright 2007 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com * * Copyright 2010-2011 Freescale Semiconductor, Inc.
*/
/* Uncomment me to enable of_dump_addr() debugging output */ // #define DEBUG
#include"of_private.h"
/* Callbacks for bus specific translators */ struct of_bus { void (*count_cells)(constvoid *blob, int parentoffset, int *addrc, int *sizec);
u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna); int (*translate)(__be32 *addr, u64 offset, int na);
};
/* Default translator (generic bus) */ staticvoid __init fdt_bus_default_count_cells(constvoid *blob, int parentoffset, int *addrc, int *sizec)
{ const __be32 *prop;
if (addrc) {
prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL); if (prop)
*addrc = be32_to_cpup(prop); else
*addrc = -1;
}
if (sizec) {
prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); if (prop)
*sizec = be32_to_cpup(prop); else
*sizec = -1;
}
}
static u64 __init fdt_bus_default_map(__be32 *addr, const __be32 *range, int na, int ns, int pna)
{
u64 cp, s, da;
cp = of_read_number(range, na);
s = of_read_number(range + na + pna, ns);
da = of_read_number(addr, na);
/* Translate it into parent bus space */ return pbus->translate(addr, offset, pna);
}
/* * Translate an address from the device-tree into a CPU physical address, * this walks up the tree and applies the various bus mappings on the * way. * * Note: We consider that crossing any level with #size-cells == 0 to mean * that translation is impossible (that is we are not dealing with a value * that can be mapped to a cpu physical address). This is not really specified * that way, but this is traditionally the way IBM at least do things
*/ static u64 __init fdt_translate_address(constvoid *blob, int node_offset)
{ int parent, len; conststruct of_bus *bus, *pbus; const __be32 *reg;
__be32 addr[OF_MAX_ADDR_CELLS]; int na, ns, pna, pns;
u64 result = OF_BAD_ADDR;
pr_debug("** translation for device %s **\n",
fdt_get_name(blob, node_offset, NULL));
reg = fdt_getprop(blob, node_offset, "reg", &len); if (!reg) {
pr_err("warning: device tree node '%s' has no address.\n",
fdt_get_name(blob, node_offset, NULL)); goto bail;
}
/* Get parent & match bus type */
parent = fdt_parent_offset(blob, node_offset); if (parent < 0) goto bail;
bus = &of_busses[0];
/* Translate */ for (;;) { /* Switch to parent bus */
node_offset = parent;
parent = fdt_parent_offset(blob, node_offset);
/* If root, we have finished */ if (parent < 0) {
pr_debug("reached root node\n");
result = of_read_number(addr, na); break;
}
/* Get new parent bus and counts */
pbus = &of_busses[0];
pbus->count_cells(blob, parent, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) {
pr_err("Bad cell count for %s\n",
fdt_get_name(blob, node_offset, NULL)); break;
}
pr_debug("parent bus (na=%d, ns=%d) on %s\n",
pna, pns, fdt_get_name(blob, parent, NULL));
/* Apply bus translation */ if (fdt_translate_one(blob, node_offset, bus, pbus,
addr, na, ns, pna, "ranges")) break;
/* Complete the move up one level */
na = pna;
ns = pns;
bus = pbus;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.