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:
parent
fc15b9beed
commit
0a222d53d8
@ -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__,
|
||||
|
@ -178,4 +178,27 @@ config SPL_OF_TRANSLATE
|
||||
used for the address translation. This function is faster and
|
||||
smaller in size than fdt_translate_address().
|
||||
|
||||
config OF_ISA_BUS
|
||||
bool
|
||||
depends on OF_TRANSLATE
|
||||
help
|
||||
Is this option is enabled then support for the ISA bus will
|
||||
be included for addresses read from DT. This is something that
|
||||
should be known to be required or not based upon the board
|
||||
being targetted, and whether or not it makes use of an ISA bus.
|
||||
|
||||
The bus is matched based upon its node name equalling "isa". The
|
||||
busses #address-cells should equal 2, with the first cell being
|
||||
used to hold flags & flag 0x1 indicating that the address range
|
||||
should be accessed using I/O port in/out accessors. The second
|
||||
cell holds the offset into ISA bus address space. The #size-cells
|
||||
property should equal 1, and of course holds the size of the
|
||||
address range used by a device.
|
||||
|
||||
If this option is not enabled then support for the ISA bus is
|
||||
not included and any such busses used in DT will be treated as
|
||||
typical simple-bus compatible busses. This will lead to
|
||||
mistranslation of device addresses, so ensure that this is
|
||||
enabled if your board does include an ISA bus.
|
||||
|
||||
endmenu
|
||||
|
Loading…
Reference in New Issue
Block a user