X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=common%2Ffdt_support.c;h=5d8eb12f10737a5eedf4d814a0406611284e7fb8;hb=2372b0012925f9100980151f4a28347c82feaba8;hp=2a20147286e6bfa53c164d93838482423d561039;hpb=d4f495a881476b557394607665a4deda7158b8c7;p=oweals%2Fu-boot.git diff --git a/common/fdt_support.c b/common/fdt_support.c index 2a20147286..5d8eb12f10 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -15,22 +16,7 @@ #include #include #include - -/* - * Get cells len in bytes - * if #NNNN-cells property is 2 then len is 8 - * otherwise len is 4 - */ -static int get_cells_len(const void *fdt, const char *nr_cells_name) -{ - const fdt32_t *cell; - - cell = fdt_getprop(fdt, 0, nr_cells_name, NULL); - if (cell && fdt32_to_cpu(*cell) == 2) - return 8; - - return 4; -} +#include /** * fdt_getprop_u32_default_node - Return a node's property or a default @@ -113,7 +99,8 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, } /** - * fdt_find_or_add_subnode - find or possibly add a subnode of a given node + * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node + * * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate @@ -121,8 +108,7 @@ int fdt_find_and_setprop(void *fdt, const char *node, const char *prop, * fdt_subnode_offset() finds a subnode of the node with a given name. * If the subnode does not exist, it will be created. */ -static int fdt_find_or_add_subnode(void *fdt, int parentoffset, - const char *name) +int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name) { int offset; @@ -145,18 +131,6 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff) OF_STDOUT_PATH, strlen(OF_STDOUT_PATH) + 1); } #elif defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX) -static void fdt_fill_multisername(char *sername, size_t maxlen) -{ - const char *outname = stdio_devices[stdout]->name; - - if (strcmp(outname, "serial") > 0) - strncpy(sername, outname, maxlen); - - /* eserial? */ - if (strcmp(outname + 1, "serial") > 0) - strncpy(sername, outname + 1, maxlen); -} - static int fdt_fixup_stdout(void *fdt, int chosenoff) { int err; @@ -166,32 +140,35 @@ static int fdt_fixup_stdout(void *fdt, int chosenoff) int len; char tmp[256]; /* long enough */ - fdt_fill_multisername(sername, sizeof(sername) - 1); - if (!sername[0]) - sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); + sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1); aliasoff = fdt_path_offset(fdt, "/aliases"); if (aliasoff < 0) { err = aliasoff; - goto error; + goto noalias; } path = fdt_getprop(fdt, aliasoff, sername, &len); if (!path) { err = len; - goto error; + goto noalias; } /* fdt_setprop may break "path" so we copy it to tmp buffer */ memcpy(tmp, path, len); err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len); -error: if (err < 0) printf("WARNING: could not set linux,stdout-path %s.\n", fdt_strerror(err)); return err; + +noalias: + printf("WARNING: %s: could not read %s alias: %s\n", + __func__, sername, fdt_strerror(err)); + + return 0; } #else static int fdt_fixup_stdout(void *fdt, int chosenoff) @@ -209,6 +186,31 @@ static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name, return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val); } +int fdt_root(void *fdt) +{ + char *serial; + int err; + + err = fdt_check_header(fdt); + if (err < 0) { + printf("fdt_root: %s\n", fdt_strerror(err)); + return err; + } + + serial = getenv("serial#"); + if (serial) { + err = fdt_setprop(fdt, 0, "serial-number", serial, + strlen(serial) + 1); + + if (err < 0) { + printf("WARNING: could not set serial-number %s.\n", + fdt_strerror(err)); + return err; + } + } + + return 0; +} int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) { @@ -246,7 +248,7 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) return err; } - is_u64 = (get_cells_len(fdt, "#address-cells") == 8); + is_u64 = (fdt_address_cells(fdt, 0) == 2); err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start", (uint64_t)initrd_start, is_u64); @@ -382,26 +384,26 @@ void do_fixup_by_compat_u32(void *fdt, const char *compat, /* * fdt_pack_reg - pack address and size array into the "reg"-suitable stream */ -static int fdt_pack_reg(const void *fdt, void *buf, uint64_t *address, - uint64_t *size, int n) +static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size, + int n) { int i; - int address_len = get_cells_len(fdt, "#address-cells"); - int size_len = get_cells_len(fdt, "#size-cells"); + int address_cells = fdt_address_cells(fdt, 0); + int size_cells = fdt_size_cells(fdt, 0); char *p = buf; for (i = 0; i < n; i++) { - if (address_len == 8) + if (address_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(address[i]); else *(fdt32_t *)p = cpu_to_fdt32(address[i]); - p += address_len; + p += 4 * address_cells; - if (size_len == 8) + if (size_cells == 2) *(fdt64_t *)p = cpu_to_fdt64(size[i]); else *(fdt32_t *)p = cpu_to_fdt32(size[i]); - p += size_len; + p += 4 * size_cells; } return p - (char *)buf; @@ -444,6 +446,9 @@ int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks) return err; } + if (!banks) + return 0; + len = fdt_pack_reg(blob, tmp, start, size, banks); err = fdt_setprop(blob, nodeoffset, "reg", tmp, len); @@ -462,48 +467,58 @@ int fdt_fixup_memory(void *blob, u64 start, u64 size) void fdt_fixup_ethernet(void *fdt) { - int node, i, j; - char enet[16], *tmp, *end; + int i, j, prop; + char *tmp, *end; char mac[16]; const char *path; unsigned char mac_addr[6]; + int offset; - node = fdt_path_offset(fdt, "/aliases"); - if (node < 0) + if (fdt_path_offset(fdt, "/aliases") < 0) return; - if (!getenv("ethaddr")) { - if (getenv("usbethaddr")) { - strcpy(mac, "usbethaddr"); - } else { - debug("No ethernet MAC Address defined\n"); - return; - } - } else { - strcpy(mac, "ethaddr"); - } + /* Cycle through all aliases */ + for (prop = 0; ; prop++) { + const char *name; + int len = strlen("ethernet"); - i = 0; - while ((tmp = getenv(mac)) != NULL) { - sprintf(enet, "ethernet%d", i); - path = fdt_getprop(fdt, node, enet, NULL); - if (!path) { - debug("No alias for %s\n", enet); - sprintf(mac, "eth%daddr", ++i); - continue; - } + /* FDT might have been edited, recompute the offset */ + offset = fdt_first_property_offset(fdt, + fdt_path_offset(fdt, "/aliases")); + /* Select property number 'prop' */ + for (i = 0; i < prop; i++) + offset = fdt_next_property_offset(fdt, offset); - for (j = 0; j < 6; j++) { - mac_addr[j] = tmp ? simple_strtoul(tmp, &end, 16) : 0; - if (tmp) - tmp = (*end) ? end+1 : end; - } + if (offset < 0) + break; - do_fixup_by_path(fdt, path, "mac-address", &mac_addr, 6, 0); - do_fixup_by_path(fdt, path, "local-mac-address", - &mac_addr, 6, 1); + path = fdt_getprop_by_offset(fdt, offset, &name, NULL); + if (!strncmp(name, "ethernet", len)) { + i = trailing_strtol(name); + if (i != -1) { + if (i == 0) + strcpy(mac, "ethaddr"); + else + sprintf(mac, "eth%daddr", i); + } else { + continue; + } + tmp = getenv(mac); + if (!tmp) + continue; + + for (j = 0; j < 6; j++) { + mac_addr[j] = tmp ? + simple_strtoul(tmp, &end, 16) : 0; + if (tmp) + tmp = (*end) ? end + 1 : end; + } - sprintf(mac, "eth%daddr", ++i); + do_fixup_by_path(fdt, path, "mac-address", + &mac_addr, 6, 0); + do_fixup_by_path(fdt, path, "local-mac-address", + &mac_addr, 6, 1); + } } } @@ -930,11 +945,9 @@ void fdt_del_node_and_alias(void *blob, const char *alias) fdt_delprop(blob, off, alias); } -#define PRu64 "%llx" - /* Max address size we deal with */ #define OF_MAX_ADDR_CELLS 4 -#define OF_BAD_ADDR ((u64)-1) +#define OF_BAD_ADDR FDT_ADDR_T_NONE #define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ (ns) > 0) @@ -951,10 +964,40 @@ static void of_dump_addr(const char *s, const fdt32_t *addr, int na) static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { } #endif -/* Callbacks for bus specific translators */ +/** + * struct of_bus - Callbacks for bus specific translators + * @name: A string used to identify this bus in debug output. + * @addresses: The name of the DT property from which addresses are + * to be read, typically "reg". + * @match: Return non-zero if the node whose parent is at + * parentoffset in the FDT blob corresponds to a bus + * of this type, otherwise return zero. If NULL a match + * is assumed. + * @count_cells:Count how many cells (be32 values) a node whose parent + * is at parentoffset in the FDT blob will require to + * represent its address (written to *addrc) & size + * (written to *sizec). + * @map: Map the address addr from the address space of this + * bus to that of its parent, making use of the ranges + * read from DT to an array at range. na and ns are the + * number of cells (be32 values) used to hold and address + * or size, respectively, for this bus. pna is the number + * of cells used to hold an address for the parent bus. + * Returns the address in the address space of the parent + * bus. + * @translate: Update the value of the address cells at addr within an + * FDT by adding offset to it. na specifies the number of + * cells used to hold the address being translated. Returns + * zero on success, non-zero on error. + * + * Each bus type will include a struct of_bus in the of_busses array, + * providing implementations of some or all of the functions used to + * match the bus & handle address translation for its children. + */ struct of_bus { const char *name; const char *addresses; + int (*match)(void *blob, int parentoffset); void (*count_cells)(void *blob, int parentoffset, int *addrc, int *sizec); u64 (*map)(fdt32_t *addr, const fdt32_t *range, @@ -968,13 +1011,8 @@ void of_bus_default_count_cells(void *blob, int parentoffset, { const fdt32_t *prop; - if (addrc) { - prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL); - if (prop) - *addrc = be32_to_cpup(prop); - else - *addrc = 2; - } + if (addrc) + *addrc = fdt_address_cells(blob, parentoffset); if (sizec) { prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL); @@ -994,8 +1032,8 @@ static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range, s = of_read_number(range + na + pna, ns); da = of_read_number(addr, na); - debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n", - cp, s, da); + debug("OF: default map, cp=%" PRIu64 ", s=%" PRIu64 + ", da=%" PRIu64 "\n", cp, s, da); if (da < cp || da >= (cp + s)) return OF_BAD_ADDR; @@ -1014,8 +1052,70 @@ static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na) return 0; } +#ifdef CONFIG_OF_ISA_BUS + +/* ISA bus translator */ +static int of_bus_isa_match(void *blob, int parentoffset) +{ + const char *name; + + name = fdt_get_name(blob, parentoffset, NULL); + if (!name) + return 0; + + return !strcmp(name, "isa"); +} + +static void of_bus_isa_count_cells(void *blob, int parentoffset, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & cpu_to_be32(1)) + return OF_BAD_ADDR; + + cp = of_read_number(range + 1, na - 1); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr + 1, na - 1); + + debug("OF: ISA map, cp=%" PRIu64 ", s=%" PRIu64 + ", da=%" PRIu64 "\n", cp, s, da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +#endif /* CONFIG_OF_ISA_BUS */ + /* Array of bus specific translators */ static struct of_bus of_busses[] = { +#ifdef CONFIG_OF_ISA_BUS + /* ISA */ + { + .name = "isa", + .addresses = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + }, +#endif /* CONFIG_OF_ISA_BUS */ /* Default */ { .name = "default", @@ -1026,6 +1126,28 @@ static struct of_bus of_busses[] = { }, }; +static struct of_bus *of_match_bus(void *blob, int parentoffset) +{ + struct of_bus *bus; + + if (ARRAY_SIZE(of_busses) == 1) + return of_busses; + + for (bus = of_busses; bus; bus++) { + if (!bus->match || bus->match(blob, parentoffset)) + return bus; + } + + /* + * We should always have matched the default bus at least, since + * it has a NULL match field. If we didn't then it somehow isn't + * in the of_busses array or something equally catastrophic has + * gone wrong. + */ + assert(0); + return NULL; +} + static int of_translate_one(void * blob, int parent, struct of_bus *bus, struct of_bus *pbus, fdt32_t *addr, int na, int ns, int pna, const char *rprop) @@ -1073,7 +1195,7 @@ static int of_translate_one(void * blob, int parent, struct of_bus *bus, finish: of_dump_addr("OF: parent translation for:", addr, pna); - debug("OF: with offset: "PRu64"\n", offset); + debug("OF: with offset: %" PRIu64 "\n", offset); /* Translate it into parent bus space */ return pbus->translate(addr, offset, pna); @@ -1105,7 +1227,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in parent = fdt_parent_offset(blob, node_offset); if (parent < 0) goto bail; - bus = &of_busses[0]; + bus = of_match_bus(blob, parent); /* Cound address cells & copy address locally */ bus->count_cells(blob, parent, &na, &ns); @@ -1134,7 +1256,7 @@ static u64 __of_translate_address(void *blob, int node_offset, const fdt32_t *in } /* Get new parent bus and counts */ - pbus = &of_busses[0]; + pbus = of_match_bus(blob, parent); pbus->count_cells(blob, parent, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) { printf("%s: Bad cell count for %s\n", __FUNCTION__, @@ -1402,9 +1524,9 @@ int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr) dt_addr = fdt_translate_address(fdt, node, reg); if (addr != dt_addr) { - printf("Warning: U-Boot configured device %s at address %llx,\n" - " but the device tree has it address %llx.\n", - alias, addr, dt_addr); + printf("Warning: U-Boot configured device %s at address %" + PRIx64 ",\n but the device tree has it address %" + PRIx64 ".\n", alias, addr, dt_addr); return 0; } @@ -1420,11 +1542,7 @@ u64 fdt_get_base_address(void *fdt, int node) u32 naddr; const fdt32_t *prop; - prop = fdt_getprop(fdt, node, "#address-cells", &size); - if (prop && size == 4) - naddr = be32_to_cpup(prop); - else - naddr = 2; + naddr = fdt_address_cells(fdt, node); prop = fdt_getprop(fdt, node, "ranges", &size); @@ -1559,7 +1677,7 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, if (ret < 0) return ret; - snprintf(name, sizeof(name), "framebuffer@%llx", base_address); + snprintf(name, sizeof(name), "framebuffer@%" PRIx64, base_address); ret = fdt_set_name(fdt, node, name); if (ret < 0) return ret; @@ -1586,3 +1704,32 @@ int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width, return 0; } + +/* + * Update native-mode in display-timings from display environment variable. + * The node to update are specified by path. + */ +int fdt_fixup_display(void *blob, const char *path, const char *display) +{ + int off, toff; + + if (!display || !path) + return -FDT_ERR_NOTFOUND; + + toff = fdt_path_offset(blob, path); + if (toff >= 0) + toff = fdt_subnode_offset(blob, toff, "display-timings"); + if (toff < 0) + return toff; + + for (off = fdt_first_subnode(blob, toff); + off >= 0; + off = fdt_next_subnode(blob, off)) { + uint32_t h = fdt_get_phandle(blob, off); + debug("%s:0x%x\n", fdt_get_name(blob, off, NULL), + fdt32_to_cpu(h)); + if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0) + return fdt_setprop_u32(blob, toff, "native-mode", h); + } + return toff; +}