diff options
Diffstat (limited to 'lib/utils/fdt/fdt_helper.c')
-rw-r--r-- | lib/utils/fdt/fdt_helper.c | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index de77196..a970c0f 100644 --- a/lib/utils/fdt/fdt_helper.c +++ b/lib/utils/fdt/fdt_helper.c @@ -72,6 +72,53 @@ int fdt_find_match(void *fdt, int startoff, return SBI_ENODEV; } +int fdt_parse_phandle_with_args(void *fdt, int nodeoff, + const char *prop, const char *cells_prop, + int index, struct fdt_phandle_args *out_args) +{ + u32 i, pcells; + int len, pnodeoff; + const fdt32_t *list, *list_end, *val; + + if (!fdt || (nodeoff < 0) || !prop || !cells_prop || !out_args) + return SBI_EINVAL; + + list = fdt_getprop(fdt, nodeoff, prop, &len); + if (!list) + return SBI_ENOENT; + list_end = list + (len / sizeof(*list)); + + while (list < list_end) { + pnodeoff = fdt_node_offset_by_phandle(fdt, + fdt32_to_cpu(*list)); + if (pnodeoff < 0) + return pnodeoff; + list++; + + val = fdt_getprop(fdt, pnodeoff, cells_prop, &len); + if (!val) + return SBI_ENOENT; + pcells = fdt32_to_cpu(*val); + if (FDT_MAX_PHANDLE_ARGS < pcells) + return SBI_EINVAL; + if (list + pcells > list_end) + return SBI_ENOENT; + + if (index > 0) { + list += pcells; + index--; + } else { + out_args->node_offset = pnodeoff; + out_args->args_count = pcells; + for (i = 0; i < pcells; i++) + out_args->args[i] = fdt32_to_cpu(list[i]); + return 0; + } + } + + return SBI_ENOENT; +} + static int fdt_translate_address(void *fdt, uint64_t reg, int parent, unsigned long *addr) { |