X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=lib%2Ffdtdec.c;h=61af3472e6a41352f3fd2f43a8d56a4b5be5e48a;hb=9c6bf1715f6afd97cb9cf79d68cc00a81d5a9efa;hp=a51dc5e98670ccf02883ef5ee03633c05db9cdf0;hpb=95f4bbd581cfde45d4bd1fa5e56c2d880dae7ced;p=oweals%2Fu-boot.git diff --git a/lib/fdtdec.c b/lib/fdtdec.c index a51dc5e986..61af3472e6 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -45,7 +47,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"), COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"), - COMPAT(GENERIC_SPI_FLASH, "spi-flash"), + COMPAT(GENERIC_SPI_FLASH, "jedec,spi-nor"), COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"), COMPAT(INTEL_MICROCODE, "intel,microcode"), COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"), @@ -184,60 +186,6 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) } #if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI) -int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, - const char *prop_name, struct fdt_pci_addr *addr) -{ - const u32 *cell; - int len; - int ret = -ENOENT; - - debug("%s: %s: ", __func__, prop_name); - - /* - * If we follow the pci bus bindings strictly, we should check - * the value of the node's parent node's #address-cells and - * #size-cells. They need to be 3 and 2 accordingly. However, - * for simplicity we skip the check here. - */ - cell = fdt_getprop(blob, node, prop_name, &len); - if (!cell) - goto fail; - - if ((len % FDT_PCI_REG_SIZE) == 0) { - int num = len / FDT_PCI_REG_SIZE; - int i; - - for (i = 0; i < num; i++) { - debug("pci address #%d: %08lx %08lx %08lx\n", i, - (ulong)fdt32_to_cpu(cell[0]), - (ulong)fdt32_to_cpu(cell[1]), - (ulong)fdt32_to_cpu(cell[2])); - if ((fdt32_to_cpu(*cell) & type) == type) { - addr->phys_hi = fdt32_to_cpu(cell[0]); - addr->phys_mid = fdt32_to_cpu(cell[1]); - addr->phys_lo = fdt32_to_cpu(cell[1]); - break; - } - - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); - } - - if (i == num) { - ret = -ENXIO; - goto fail; - } - - return 0; - } - - ret = -EINVAL; - -fail: - debug("(not found)\n"); - return ret; -} - int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device) { const char *list, *end; @@ -294,7 +242,7 @@ int fdtdec_get_pci_bar32(struct udevice *dev, struct fdt_pci_addr *addr, uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name, uint64_t default_val) { - const uint64_t *cell64; + const unaligned_fdt64_t *cell64; int length; cell64 = fdt_getprop(blob, node, prop_name, &length); @@ -1261,6 +1209,260 @@ __weak void *board_fdt_blob_setup(void) } #endif +int fdtdec_set_ethernet_mac_address(void *fdt, const u8 *mac, size_t size) +{ + const char *path; + int offset, err; + + if (!is_valid_ethaddr(mac)) + return -EINVAL; + + path = fdt_get_alias(fdt, "ethernet"); + if (!path) + return 0; + + debug("ethernet alias found: %s\n", path); + + offset = fdt_path_offset(fdt, path); + if (offset < 0) { + debug("ethernet alias points to absent node %s\n", path); + return -ENOENT; + } + + err = fdt_setprop_inplace(fdt, offset, "local-mac-address", mac, size); + if (err < 0) + return err; + + debug("MAC address: %pM\n", mac); + + return 0; +} + +static int fdtdec_init_reserved_memory(void *blob) +{ + int na, ns, node, err; + fdt32_t value; + + /* inherit #address-cells and #size-cells from the root node */ + na = fdt_address_cells(blob, 0); + ns = fdt_size_cells(blob, 0); + + node = fdt_add_subnode(blob, 0, "reserved-memory"); + if (node < 0) + return node; + + err = fdt_setprop(blob, node, "ranges", NULL, 0); + if (err < 0) + return err; + + value = cpu_to_fdt32(ns); + + err = fdt_setprop(blob, node, "#size-cells", &value, sizeof(value)); + if (err < 0) + return err; + + value = cpu_to_fdt32(na); + + err = fdt_setprop(blob, node, "#address-cells", &value, sizeof(value)); + if (err < 0) + return err; + + return node; +} + +int fdtdec_add_reserved_memory(void *blob, const char *basename, + const struct fdt_memory *carveout, + uint32_t *phandlep) +{ + fdt32_t cells[4] = {}, *ptr = cells; + uint32_t upper, lower, phandle; + int parent, node, na, ns, err; + fdt_size_t size; + char name[64]; + + /* create an empty /reserved-memory node if one doesn't exist */ + parent = fdt_path_offset(blob, "/reserved-memory"); + if (parent < 0) { + parent = fdtdec_init_reserved_memory(blob); + if (parent < 0) + return parent; + } + + /* only 1 or 2 #address-cells and #size-cells are supported */ + na = fdt_address_cells(blob, parent); + if (na < 1 || na > 2) + return -FDT_ERR_BADNCELLS; + + ns = fdt_size_cells(blob, parent); + if (ns < 1 || ns > 2) + return -FDT_ERR_BADNCELLS; + + /* find a matching node and return the phandle to that */ + fdt_for_each_subnode(node, blob, parent) { + const char *name = fdt_get_name(blob, node, NULL); + phys_addr_t addr, size; + + addr = fdtdec_get_addr_size(blob, node, "reg", &size); + if (addr == FDT_ADDR_T_NONE) { + debug("failed to read address/size for %s\n", name); + continue; + } + + if (addr == carveout->start && (addr + size) == carveout->end) { + if (phandlep) + *phandlep = fdt_get_phandle(blob, node); + return 0; + } + } + + /* + * Unpack the start address and generate the name of the new node + * base on the basename and the unit-address. + */ + upper = upper_32_bits(carveout->start); + lower = lower_32_bits(carveout->start); + + if (na > 1 && upper > 0) + snprintf(name, sizeof(name), "%s@%x,%x", basename, upper, + lower); + else { + if (upper > 0) { + debug("address %08x:%08x exceeds addressable space\n", + upper, lower); + return -FDT_ERR_BADVALUE; + } + + snprintf(name, sizeof(name), "%s@%x", basename, lower); + } + + node = fdt_add_subnode(blob, parent, name); + if (node < 0) + return node; + + if (phandlep) { + err = fdt_generate_phandle(blob, &phandle); + if (err < 0) + return err; + + err = fdtdec_set_phandle(blob, node, phandle); + if (err < 0) + return err; + } + + /* store one or two address cells */ + if (na > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + /* store one or two size cells */ + size = carveout->end - carveout->start + 1; + upper = upper_32_bits(size); + lower = lower_32_bits(size); + + if (ns > 1) + *ptr++ = cpu_to_fdt32(upper); + + *ptr++ = cpu_to_fdt32(lower); + + err = fdt_setprop(blob, node, "reg", cells, (na + ns) * sizeof(*cells)); + if (err < 0) + return err; + + /* return the phandle for the new node for the caller to use */ + if (phandlep) + *phandlep = phandle; + + return 0; +} + +int fdtdec_get_carveout(const void *blob, const char *node, const char *name, + unsigned int index, struct fdt_memory *carveout) +{ + const fdt32_t *prop; + uint32_t phandle; + int offset, len; + fdt_size_t size; + + offset = fdt_path_offset(blob, node); + if (offset < 0) + return offset; + + prop = fdt_getprop(blob, offset, name, &len); + if (!prop) { + debug("failed to get %s for %s\n", name, node); + return -FDT_ERR_NOTFOUND; + } + + if ((len % sizeof(phandle)) != 0) { + debug("invalid phandle property\n"); + return -FDT_ERR_BADPHANDLE; + } + + if (len < (sizeof(phandle) * (index + 1))) { + debug("invalid phandle index\n"); + return -FDT_ERR_BADPHANDLE; + } + + phandle = fdt32_to_cpu(prop[index]); + + offset = fdt_node_offset_by_phandle(blob, phandle); + if (offset < 0) { + debug("failed to find node for phandle %u\n", phandle); + return offset; + } + + carveout->start = fdtdec_get_addr_size_auto_noparent(blob, offset, + "reg", 0, &size, + true); + if (carveout->start == FDT_ADDR_T_NONE) { + debug("failed to read address/size from \"reg\" property\n"); + return -FDT_ERR_NOTFOUND; + } + + carveout->end = carveout->start + size - 1; + + return 0; +} + +int fdtdec_set_carveout(void *blob, const char *node, const char *prop_name, + unsigned int index, const char *name, + const struct fdt_memory *carveout) +{ + uint32_t phandle; + int err, offset; + fdt32_t value; + + /* XXX implement support for multiple phandles */ + if (index > 0) { + debug("invalid index %u\n", index); + return -FDT_ERR_BADOFFSET; + } + + err = fdtdec_add_reserved_memory(blob, name, carveout, &phandle); + if (err < 0) { + debug("failed to add reserved memory: %d\n", err); + return err; + } + + offset = fdt_path_offset(blob, node); + if (offset < 0) { + debug("failed to find offset for node %s: %d\n", node, offset); + return offset; + } + + value = cpu_to_fdt32(phandle); + + err = fdt_setprop(blob, offset, prop_name, &value, sizeof(value)); + if (err < 0) { + debug("failed to set %s property for node %s: %d\n", prop_name, + node, err); + return err; + } + + return 0; +} + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) @@ -1282,16 +1484,14 @@ int fdtdec_setup(void) puts("Failed to read control FDT\n"); return -1; } +# elif defined(CONFIG_OF_PRIOR_STAGE) + gd->fdt_blob = (void *)prior_stage_fdt_address; # endif # ifndef CONFIG_SPL_BUILD /* Allow the early environment to override the fdt address */ -# if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) - gd->fdt_blob = (void *)prior_stage_fdt_address; -# else gd->fdt_blob = map_sysmem (env_get_ulong("fdtcontroladdr", 16, (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); -# endif # endif # if CONFIG_IS_ENABLED(MULTI_DTB_FIT)