|
@@ -964,10 +964,21 @@ static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
|
|
|
static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { }
|
|
|
#endif
|
|
|
|
|
|
-/* Callbacks for bus specific translators */
|
|
|
+/**
|
|
|
+ * struct of_bus - Callbacks for bus specific translators
|
|
|
+ * @match: Return non-zero if the node whose parent is at
|
|
|
+ * parentoffset in the FDT blob corresponds to a bus
|
|
|
+ * of this type, otherwise return zero. If NULL a match
|
|
|
+ * is assumed.
|
|
|
+ *
|
|
|
+ * Each bus type will include a struct of_bus in the of_busses array,
|
|
|
+ * providing implementations of some or all of the functions used to
|
|
|
+ * match the bus & handle address translation for its children.
|
|
|
+ */
|
|
|
struct of_bus {
|
|
|
const char *name;
|
|
|
const char *addresses;
|
|
|
+ int (*match)(void *blob, int parentoffset);
|
|
|
void (*count_cells)(void *blob, int parentoffset,
|
|
|
int *addrc, int *sizec);
|
|
|
u64 (*map)(fdt32_t *addr, const fdt32_t *range,
|
|
@@ -1022,8 +1033,70 @@ static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_OF_ISA_BUS
|
|
|
+
|
|
|
+/* ISA bus translator */
|
|
|
+static int of_bus_isa_match(void *blob, int parentoffset)
|
|
|
+{
|
|
|
+ const char *name;
|
|
|
+
|
|
|
+ name = fdt_get_name(blob, parentoffset, NULL);
|
|
|
+ if (!name)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ return !strcmp(name, "isa");
|
|
|
+}
|
|
|
+
|
|
|
+static void of_bus_isa_count_cells(void *blob, int parentoffset,
|
|
|
+ int *addrc, int *sizec)
|
|
|
+{
|
|
|
+ if (addrc)
|
|
|
+ *addrc = 2;
|
|
|
+ if (sizec)
|
|
|
+ *sizec = 1;
|
|
|
+}
|
|
|
+
|
|
|
+static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range,
|
|
|
+ int na, int ns, int pna)
|
|
|
+{
|
|
|
+ u64 cp, s, da;
|
|
|
+
|
|
|
+ /* Check address type match */
|
|
|
+ if ((addr[0] ^ range[0]) & cpu_to_be32(1))
|
|
|
+ return OF_BAD_ADDR;
|
|
|
+
|
|
|
+ cp = of_read_number(range + 1, na - 1);
|
|
|
+ s = of_read_number(range + na + pna, ns);
|
|
|
+ da = of_read_number(addr + 1, na - 1);
|
|
|
+
|
|
|
+ debug("OF: ISA map, cp=%" PRIu64 ", s=%" PRIu64
|
|
|
+ ", da=%" PRIu64 "\n", cp, s, da);
|
|
|
+
|
|
|
+ if (da < cp || da >= (cp + s))
|
|
|
+ return OF_BAD_ADDR;
|
|
|
+ return da - cp;
|
|
|
+}
|
|
|
+
|
|
|
+static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na)
|
|
|
+{
|
|
|
+ return of_bus_default_translate(addr + 1, offset, na - 1);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* CONFIG_OF_ISA_BUS */
|
|
|
+
|
|
|
/* Array of bus specific translators */
|
|
|
static struct of_bus of_busses[] = {
|
|
|
+#ifdef CONFIG_OF_ISA_BUS
|
|
|
+ /* ISA */
|
|
|
+ {
|
|
|
+ .name = "isa",
|
|
|
+ .addresses = "reg",
|
|
|
+ .match = of_bus_isa_match,
|
|
|
+ .count_cells = of_bus_isa_count_cells,
|
|
|
+ .map = of_bus_isa_map,
|
|
|
+ .translate = of_bus_isa_translate,
|
|
|
+ },
|
|
|
+#endif /* CONFIG_OF_ISA_BUS */
|
|
|
/* Default */
|
|
|
{
|
|
|
.name = "default",
|
|
@@ -1034,6 +1107,28 @@ static struct of_bus of_busses[] = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+static struct of_bus *of_match_bus(void *blob, int parentoffset)
|
|
|
+{
|
|
|
+ struct of_bus *bus;
|
|
|
+
|
|
|
+ if (ARRAY_SIZE(of_busses) == 1)
|
|
|
+ return of_busses;
|
|
|
+
|
|
|
+ for (bus = of_busses; bus; bus++) {
|
|
|
+ if (!bus->match || bus->match(blob, parentoffset))
|
|
|
+ return bus;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We should always have matched the default bus at least, since
|
|
|
+ * it has a NULL match field. If we didn't then it somehow isn't
|
|
|
+ * in the of_busses array or something equally catastrophic has
|
|
|
+ * gone wrong.
|
|
|
+ */
|
|
|
+ assert(0);
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
static int of_translate_one(void * blob, int parent, struct of_bus *bus,
|
|
|
struct of_bus *pbus, fdt32_t *addr,
|
|
|
int na, int ns, int pna, const char *rprop)
|
|
@@ -1113,7 +1208,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in
|
|
|
parent = fdt_parent_offset(blob, node_offset);
|
|
|
if (parent < 0)
|
|
|
goto bail;
|
|
|
- bus = &of_busses[0];
|
|
|
+ bus = of_match_bus(blob, parent);
|
|
|
|
|
|
/* Cound address cells & copy address locally */
|
|
|
bus->count_cells(blob, parent, &na, &ns);
|
|
@@ -1142,7 +1237,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in
|
|
|
}
|
|
|
|
|
|
/* Get new parent bus and counts */
|
|
|
- pbus = &of_busses[0];
|
|
|
+ pbus = of_match_bus(blob, parent);
|
|
|
pbus->count_cells(blob, parent, &pna, &pns);
|
|
|
if (!OF_CHECK_COUNTS(pna, pns)) {
|
|
|
printf("%s: Bad cell count for %s\n", __FUNCTION__,
|