diff options
-rw-r--r-- | include/fdtdec.h | 27 | ||||
-rw-r--r-- | lib/fdtdec.c | 61 |
2 files changed, 88 insertions, 0 deletions
diff --git a/include/fdtdec.h b/include/fdtdec.h index 1a931e8..a7655dc 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -677,4 +677,31 @@ int fdt_get_named_resource(const void *fdt, int node, const char *property, */ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf); +/** + * Decode a named region within a memory bank of a given type. + * + * This function handles selection of a memory region. The region is + * specified as an offset/size within a particular type of memory. + * + * The properties used are: + * + * <mem_type>-memory<suffix> for the name of the memory bank + * <mem_type>-offset<suffix> for the offset in that bank + * + * The property value must have an offset and a size. The function checks + * that the region is entirely within the memory bank.5 + * + * @param blob FDT blob + * @param node Node containing the properties (-1 for /config) + * @param mem_type Type of memory to use, which is a name, such as + * "u-boot" or "kernel". + * @param suffix String to append to the memory/offset + * property names + * @param basep Returns base of region + * @param sizep Returns size of region + * @return 0 if OK, -ive on error + */ +int fdtdec_decode_memory_region(const void *blob, int node, + const char *mem_type, const char *suffix, + fdt_addr_t *basep, fdt_size_t *sizep); #endif diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4dbd6ae..9c332ad 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -793,4 +793,65 @@ int fdtdec_pci_get_bdf(const void *fdt, int node, int *bdf) return 0; } + +int fdtdec_decode_memory_region(const void *blob, int config_node, + const char *mem_type, const char *suffix, + fdt_addr_t *basep, fdt_size_t *sizep) +{ + char prop_name[50]; + const char *mem; + fdt_size_t size, offset_size; + fdt_addr_t base, offset; + int node; + + if (config_node == -1) { + config_node = fdt_path_offset(blob, "/config"); + if (config_node < 0) { + debug("%s: Cannot find /config node\n", __func__); + return -ENOENT; + } + } + if (!suffix) + suffix = ""; + + snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type, + suffix); + mem = fdt_getprop(blob, config_node, prop_name, NULL); + if (!mem) { + debug("%s: No memory type for '%s', using /memory\n", __func__, + prop_name); + mem = "/memory"; + } + + node = fdt_path_offset(blob, mem); + if (node < 0) { + debug("%s: Failed to find node '%s': %s\n", __func__, mem, + fdt_strerror(node)); + return -ENOENT; + } + + /* + * Not strictly correct - the memory may have multiple banks. We just + * use the first + */ + if (fdtdec_decode_region(blob, node, "reg", &base, &size)) { + debug("%s: Failed to decode memory region %s\n", __func__, + mem); + return -EINVAL; + } + + snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type, + suffix); + if (fdtdec_decode_region(blob, config_node, prop_name, &offset, + &offset_size)) { + debug("%s: Failed to decode memory region '%s'\n", __func__, + prop_name); + return -EINVAL; + } + + *basep = base + offset; + *sizep = offset_size; + + return 0; +} #endif |