1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 00:32:04 +02:00

fdt: Support for ISA busses

Support ISA busses in much the same way as Linux does. This allows for
ISA bus addresses to be translated, and only if CONFIG_OF_ISA_BUS is
selected in order to avoid including the code in builds which won't need
it.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Paul Burton
2016-05-17 07:43:24 +01:00
committed by Daniel Schwierzeck
parent fc15b9beed
commit 0a222d53d8
2 changed files with 121 additions and 3 deletions

View File

@@ -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__,