int fdt_get_resource(const void *fdt, int node, const char *property, unsigned int index, struct fdt_resource *res) { const fdt32_t *ptr, *end; int na, ns, len, parent; unsigned int i = 0; parent = fdt_parent_offset(fdt, node); if (parent < 0) return parent; na = fdt_address_cells(fdt, parent); ns = fdt_size_cells(fdt, parent); ptr = fdt_getprop(fdt, node, property, &len); if (!ptr) return len; end = ptr + len / sizeof(*ptr); while (ptr + na + ns <= end) { if (i == index) { res->start = res->end = fdtdec_get_number(ptr, na); res->end += fdtdec_get_number(&ptr[na], ns) - 1; return 0; } ptr += na + ns; i++; } return -FDT_ERR_NOTFOUND; }
fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node, const char *prop_name, int index, int na, int ns, fdt_size_t *sizep, bool translate) { const fdt32_t *prop, *prop_end; const fdt32_t *prop_addr, *prop_size, *prop_after_size; int len; fdt_addr_t addr; debug("%s: %s: ", __func__, prop_name); if (na > (sizeof(fdt_addr_t) / sizeof(fdt32_t))) { debug("(na too large for fdt_addr_t type)\n"); return FDT_ADDR_T_NONE; } if (ns > (sizeof(fdt_size_t) / sizeof(fdt32_t))) { debug("(ns too large for fdt_size_t type)\n"); return FDT_ADDR_T_NONE; } prop = fdt_getprop(blob, node, prop_name, &len); if (!prop) { debug("(not found)\n"); return FDT_ADDR_T_NONE; } prop_end = prop + (len / sizeof(*prop)); prop_addr = prop + (index * (na + ns)); prop_size = prop_addr + na; prop_after_size = prop_size + ns; if (prop_after_size > prop_end) { debug("(not enough data: expected >= %d cells, got %d cells)\n", (u32)(prop_after_size - prop), ((u32)(prop_end - prop))); return FDT_ADDR_T_NONE; } #if CONFIG_IS_ENABLED(OF_TRANSLATE) if (translate) addr = fdt_translate_address(blob, node, prop_addr); else #endif addr = fdtdec_get_number(prop_addr, na); if (sizep) { *sizep = fdtdec_get_number(prop_size, ns); debug("addr=%08llx, size=%llx\n", (unsigned long long)addr, (unsigned long long)*sizep); } else { debug("addr=%08llx\n", (unsigned long long)addr); } return addr; }
fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, const char *prop_name, fdt_size_t *sizep) { const fdt32_t *ptr, *end; int parent, na, ns, len; fdt_addr_t addr; debug("%s: %s: ", __func__, prop_name); parent = fdt_parent_offset(blob, node); if (parent < 0) { debug("(no parent found)\n"); return FDT_ADDR_T_NONE; } na = fdt_address_cells(blob, parent); ns = fdt_size_cells(blob, parent); ptr = fdt_getprop(blob, node, prop_name, &len); if (!ptr) { debug("(not found)\n"); return FDT_ADDR_T_NONE; } end = ptr + len / sizeof(*ptr); if (ptr + na + ns > end) { debug("(not enough data: expected %d bytes, got %d bytes)\n", (na + ns) * 4, len); return FDT_ADDR_T_NONE; } addr = fdtdec_get_number(ptr, na); if (sizep) { *sizep = fdtdec_get_number(ptr + na, ns); debug("addr=%pa, size=%pa\n", &addr, sizep); } else { debug("%pa\n", &addr); } return addr; }
static void *map_syscon_chipselects(struct udevice *bus) { #if CONFIG_IS_ENABLED(SYSCON) struct udevice *syscon; struct regmap *regmap; const fdt32_t *cell; int len, err; err = uclass_get_device_by_phandle(UCLASS_SYSCON, bus, "syscon-chipselects", &syscon); if (err) { debug("%s: unable to find syscon device (%d)\n", __func__, err); return NULL; } regmap = syscon_get_regmap(syscon); if (IS_ERR(regmap)) { debug("%s: unable to find regmap (%ld)\n", __func__, PTR_ERR(regmap)); return NULL; } cell = fdt_getprop(gd->fdt_blob, dev_of_offset(bus), "syscon-chipselects", &len); if (len < 2*sizeof(fdt32_t)) { debug("%s: offset not available\n", __func__); return NULL; } return fdtdec_get_number(cell + 1, 1) + regmap_get_range(regmap, 0); #else fdt_addr_t addr; addr = devfdt_get_addr_index(bus, 2); return (addr == FDT_ADDR_T_NONE) ? NULL : map_physmem(addr, 0, MAP_NOCACHE); #endif }
static void *get_reg(struct udevice *dev, const char *name) { struct udevice *syscon; struct regmap *regmap; const fdt32_t *cell; int len, err; void *base; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, name, &syscon); if (err) { pr_err("unable to find syscon device for %s (%d)\n", name, err); return NULL; } regmap = syscon_get_regmap(syscon); if (IS_ERR(regmap)) { pr_err("unable to find regmap for %s (%ld)\n", name, PTR_ERR(regmap)); return NULL; } cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name, &len); if (len < 2*sizeof(fdt32_t)) { pr_err("offset not available for %s\n", name); return NULL; } base = regmap_get_range(regmap, 0); if (!base) return NULL; return fdtdec_get_number(cell + 1, 1) + base; }