fdt_support: Add helper function to read "ranges" property
This patch adds a helper function that can be used to interpret most "ranges" properties in the device tree. It reads the n'th range out of a "ranges" array and returns the node's virtual address of the range, the physical address that range starts at and the size of the range. Signed-off-by: Alexander Graf <agraf@suse.de> Acked-by: Scott Wood <scottwood@freescale.com> Reviewed-by: York Sun <yorksun@freescale.com>
This commit is contained in:
parent
94fb182cdf
commit
c48e686889
@ -1435,3 +1435,97 @@ u64 fdt_get_base_address(void *fdt, int node)
|
|||||||
|
|
||||||
return prop ? fdt_translate_address(fdt, node, prop + naddr) : 0;
|
return prop ? fdt_translate_address(fdt, node, prop + naddr) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a property of size <prop_len>. Currently only supports 1 or 2 cells.
|
||||||
|
*/
|
||||||
|
static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off,
|
||||||
|
uint64_t *val, int cells)
|
||||||
|
{
|
||||||
|
const fdt32_t *prop32 = &prop[cell_off];
|
||||||
|
const fdt64_t *prop64 = (const fdt64_t *)&prop[cell_off];
|
||||||
|
|
||||||
|
if ((cell_off + cells) > prop_len)
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
|
||||||
|
switch (cells) {
|
||||||
|
case 1:
|
||||||
|
*val = fdt32_to_cpu(*prop32);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*val = fdt64_to_cpu(*prop64);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -FDT_ERR_NOSPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fdt_read_range - Read a node's n'th range property
|
||||||
|
*
|
||||||
|
* @fdt: ptr to device tree
|
||||||
|
* @node: offset of node
|
||||||
|
* @n: range index
|
||||||
|
* @child_addr: pointer to storage for the "child address" field
|
||||||
|
* @addr: pointer to storage for the CPU view translated physical start
|
||||||
|
* @len: pointer to storage for the range length
|
||||||
|
*
|
||||||
|
* Convenience function that reads and interprets a specific range out of
|
||||||
|
* a number of the "ranges" property array.
|
||||||
|
*/
|
||||||
|
int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
|
||||||
|
uint64_t *addr, uint64_t *len)
|
||||||
|
{
|
||||||
|
int pnode = fdt_parent_offset(fdt, node);
|
||||||
|
const fdt32_t *ranges;
|
||||||
|
int pacells;
|
||||||
|
int acells;
|
||||||
|
int scells;
|
||||||
|
int ranges_len;
|
||||||
|
int cell = 0;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "ranges" property is an array of
|
||||||
|
* { <child address> <parent address> <size in child address space> }
|
||||||
|
*
|
||||||
|
* All 3 elements can span a diffent number of cells. Fetch their size.
|
||||||
|
*/
|
||||||
|
pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1);
|
||||||
|
acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1);
|
||||||
|
scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1);
|
||||||
|
|
||||||
|
/* Now try to get the ranges property */
|
||||||
|
ranges = fdt_getprop(fdt, node, "ranges", &ranges_len);
|
||||||
|
if (!ranges)
|
||||||
|
return -FDT_ERR_NOTFOUND;
|
||||||
|
ranges_len /= sizeof(uint32_t);
|
||||||
|
|
||||||
|
/* Jump to the n'th entry */
|
||||||
|
cell = n * (pacells + acells + scells);
|
||||||
|
|
||||||
|
/* Read <child address> */
|
||||||
|
if (child_addr) {
|
||||||
|
r = fdt_read_prop(ranges, ranges_len, cell, child_addr,
|
||||||
|
acells);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
cell += acells;
|
||||||
|
|
||||||
|
/* Read <parent address> */
|
||||||
|
if (addr)
|
||||||
|
*addr = fdt_translate_address(fdt, node, ranges + cell);
|
||||||
|
cell += pacells;
|
||||||
|
|
||||||
|
/* Read <size in child address space> */
|
||||||
|
if (len) {
|
||||||
|
r = fdt_read_prop(ranges, ranges_len, cell, len, scells);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -87,6 +87,8 @@ int fdt_add_edid(void *blob, const char *compat, unsigned char *buf);
|
|||||||
int fdt_verify_alias_address(void *fdt, int anode, const char *alias,
|
int fdt_verify_alias_address(void *fdt, int anode, const char *alias,
|
||||||
u64 addr);
|
u64 addr);
|
||||||
u64 fdt_get_base_address(void *fdt, int node);
|
u64 fdt_get_base_address(void *fdt, int node);
|
||||||
|
int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
|
||||||
|
uint64_t *addr, uint64_t *len);
|
||||||
|
|
||||||
enum fdt_status {
|
enum fdt_status {
|
||||||
FDT_STATUS_OKAY,
|
FDT_STATUS_OKAY,
|
||||||
|
Loading…
Reference in New Issue
Block a user