/* Find the I2C buses selected by this mux */ static int i2c_mux_post_bind(struct udevice *mux) { const void *blob = gd->fdt_blob; int ret; int offset; debug("%s: %s\n", __func__, mux->name); /* * There is no compatible string in the sub-nodes, so we must manually * bind these */ for (offset = fdt_first_subnode(blob, mux->of_offset); offset > 0; offset = fdt_next_subnode(blob, offset)) { struct udevice *dev; const char *name; name = fdt_get_name(blob, offset, NULL); ret = device_bind_driver_to_node(mux, "i2c_mux_bus_drv", name, offset, &dev); debug(" - bind ret=%d, %s\n", ret, dev ? dev->name : NULL); if (ret) return ret; } return 0; }
static void parse_node(const char *dtb, int node, void (*mem_cb)(uint32_t addr, uint32_t length)) { int parent = node; node = fdt_first_subnode(dtb, node); while(node >= 0) { const void *dt; int plen; dt = fdt_getprop(dtb, node, "device_type", &plen); #ifdef DEBUG_DTB const char *nn; nn = fdt_get_name(dtb, node, NULL); if(dt != NULL && nn != NULL) { printf("DTB: found device_type property for %s: %s\n", nn, (const char *)dt); } else if(nn != NULL) printf("DTB: found node %s\n", nn); else printf("DTB: unknown node\n"); #endif if(dt != NULL && !strcmp((const char *)dt, "memory")) { parse_reg(dtb, node, parent, mem_cb); } parse_node(dtb, node, mem_cb); node = fdt_next_subnode(dtb, node); } }
/* Get the value of a property of a package. */ static ssize_t ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, size_t buflen) { const void *prop; const char *name; int len, offset; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); if (strcmp(propname, "name") == 0) { /* Emulate the 'name' property */ name = fdt_get_name(fdtp, offset, &len); strncpy(buf, name, buflen); if (len + 1 > buflen) len = buflen; return (len + 1); } prop = fdt_getprop(fdtp, offset, propname, &len); if (prop == NULL) return (-1); if (len > buflen) len = buflen; bcopy(prop, buf, len); return (len); }
/* * process_usb_nodes() - Process a list of USB nodes, adding them to our list * of USB ports. * @blob: fdt blob * @node_list: list of nodes to process (any <=0 are ignored) * @count: number of nodes to process * * Return: 0 - ok, -1 - error */ static int process_usb_nodes(const void *blob, int node_list[], int count) { struct fdt_usb config; int node, i; int clk_done = 0; port_count = 0; for (i = 0; i < count; i++) { if (port_count == USB_PORTS_MAX) { printf("tegrausb: Cannot register more than %d ports\n", USB_PORTS_MAX); return -1; } debug("USB %d: ", i); node = node_list[i]; if (!node) continue; if (fdt_decode_usb(blob, node, &config)) { debug("Cannot decode USB node %s\n", fdt_get_name(blob, node, NULL)); return -1; } if (!clk_done) { config_clock(get_pll_timing()); clk_done = 1; } config.initialized = 0; /* add new USB port to the list of available ports */ port[port_count++] = config; } return 0; }
int state_setprop(int node, const char *prop_name, const void *data, int size) { void *blob; int len; int ret; fdt_getprop(state->state_fdt, node, prop_name, &len); /* Add space for the new property, its name and some overhead */ ret = state_ensure_space(size - len + strlen(prop_name) + 32); if (ret) return ret; /* This should succeed, barring a mutiny */ blob = state->state_fdt; ret = fdt_setprop(blob, node, prop_name, data, size); if (ret) { printf("%s: Unable to set property '%s' in node '%s': %s\n", __func__, prop_name, fdt_get_name(blob, node, NULL), fdt_strerror(ret)); return -ENOSPC; } return 0; }
/* Get the length of a property of a package. */ static ssize_t ofw_fdt_getproplen(ofw_t ofw, phandle_t package, const char *propname) { const struct fdt_property *prop; int offset, len; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); len = -1; prop = fdt_get_property(fdtp, offset, propname, &len); if (prop == NULL && strcmp(propname, "name") == 0) { /* Emulate the 'name' property */ fdt_get_name(fdtp, offset, &len); return (len + 1); } if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) { if (strcmp(propname, "fdtbootcpu") == 0) return (sizeof(cell_t)); if (strcmp(propname, "fdtmemreserv") == 0) return (sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp)); } if (prop == NULL) return (-1); return (len); }
int dm_check_devices(struct dm_test_state *dms, int num_devices) { struct udevice *dev; int ret; int i; /* * Now check that the ping adds are what we expect. This is using the * ping-add property in each node. */ for (i = 0; i < num_devices; i++) { uint32_t base; ret = uclass_get_device(UCLASS_TEST_FDT, i, &dev); ut_assert(!ret); /* * Get the 'ping-expect' property, which tells us what the * ping add should be. We don't use the platdata because we * want to test the code that sets that up * (testfdt_drv_probe()). */ base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "ping-expect"); debug("dev=%d, base=%d: %s\n", i, base, fdt_get_name(gd->fdt_blob, dev->of_offset, NULL)); ut_assert(!dm_check_operations(dms, dev, base, dev_get_priv(dev))); } return 0; }
int board_usb_init(const void *blob) { struct fdt_usb config; unsigned osc_freq = clock_get_rate(CLOCK_ID_OSC); enum clock_osc_freq freq; int node_list[USB_PORTS_MAX]; int node, count, i; /* Set up the USB clocks correctly based on our oscillator frequency */ freq = clock_get_osc_freq(); config_clock(usb_pll[freq]); /* count may return <0 on error */ count = fdtdec_find_aliases_for_id(blob, "usb", COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX); for (i = 0; i < count; i++) { debug("USB %d: ", i); node = node_list[i]; if (!node) continue; if (fdt_decode_usb(blob, node, osc_freq, &config)) { debug("Cannot decode USB node %s\n", fdt_get_name(blob, node, NULL)); return -1; } if (add_port(&config, usb_pll[freq])) return -1; set_host_mode(&config); } port_current = -1; return 0; }
static int sopc_device_probe(FDTMachineInfo *fdti, const char *node_path, int pass, uint32_t offset) { DevInfo **dev = &(devices[0]); while (*dev) { const char **compat = &((*dev)->compat[0]); while (*compat) { if (0 == fdt_node_check_compatible(fdti->fdt, fdt_path_offset(fdti->fdt, node_path), *compat)) { if (pass == (*dev)->pass) { printf("Adding a device for node %s\n", fdt_get_name(fdti->fdt, fdt_path_offset(fdti->fdt, node_path), NULL)); (*dev)->probe(fdti, node_path, offset); return 0; } if (pass < (*dev)->pass) { /* Probe again on the next pass */ return 1; } } compat++; } dev++; } return 0; }
static int tegra_xusb_padctl_config_parse_dt(struct tegra_xusb_padctl *padctl, struct tegra_xusb_padctl_config *config, const void *fdt, int node) { int subnode; config->name = fdt_get_name(fdt, node, NULL); fdt_for_each_subnode(subnode, fdt, node) { struct tegra_xusb_padctl_group *group; int err; group = &config->groups[config->num_groups]; err = tegra_xusb_padctl_group_parse_dt(padctl, group, fdt, subnode); if (err < 0) { error("failed to parse group %s", group->name); return err; } config->num_groups++; } return 0; }
static int _gpio_request_by_name_nodev(const void *blob, int node, const char *list_name, int index, struct gpio_desc *desc, int flags, bool add_index) { struct fdtdec_phandle_args args; int ret; desc->dev = NULL; desc->offset = 0; ret = fdtdec_parse_phandle_with_args(blob, node, list_name, "#gpio-cells", 0, index, &args); if (ret) { debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__); goto err; } ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node, &desc->dev); if (ret) { debug("%s: uclass_get_device_by_of_offset failed\n", __func__); goto err; } ret = gpio_find_and_xlate(desc, &args); if (ret) { debug("%s: gpio_find_and_xlate failed\n", __func__); goto err; } ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s", fdt_get_name(blob, node, NULL), list_name, index); if (ret) { debug("%s: dm_gpio_requestf failed\n", __func__); goto err; } ret = dm_gpio_set_dir_flags(desc, flags | desc->flags); if (ret) { debug("%s: dm_gpio_set_dir failed\n", __func__); goto err; } return 0; err: debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n", __func__, fdt_get_name(blob, node, NULL), list_name, index, ret); return ret; }
void platform_early_init(void) { /* initialize the interrupt controller */ arm_gic_init(); arm_generic_timer_init(ARM_GENERIC_TIMER_PHYSICAL_INT, 0); uart_init_early(); /* look for a flattened device tree just before the kernel */ const void *fdt = (void *)KERNEL_BASE; int err = fdt_check_header(fdt); if (err >= 0) { /* walk the nodes, looking for 'memory' */ int depth = 0; int offset = 0; for (;;) { offset = fdt_next_node(fdt, offset, &depth); if (offset < 0) break; /* get the name */ const char *name = fdt_get_name(fdt, offset, NULL); if (!name) continue; /* look for the 'memory' property */ if (strcmp(name, "memory") == 0) { int lenp; const void *prop_ptr = fdt_getprop(fdt, offset, "reg", &lenp); if (prop_ptr && lenp == 0x10) { /* we're looking at a memory descriptor */ //uint64_t base = fdt64_to_cpu(*(uint64_t *)prop_ptr); uint64_t len = fdt64_to_cpu(*((const uint64_t *)prop_ptr + 1)); /* trim size on certain platforms */ #if ARCH_ARM if (len > 1024*1024*1024U) { len = 1024*1024*1024; /* only use the first 1GB on ARM32 */ printf("trimming memory to 1GB\n"); } #endif /* set the size in the pmm arena */ arena.size = len; } } } } /* add the main memory arena */ pmm_add_arena(&arena); /* reserve the first 64k of ram, which should be holding the fdt */ struct list_node list = LIST_INITIAL_VALUE(list); pmm_alloc_range(MEMBASE, 0x10000 / PAGE_SIZE, &list); }
static void setup_axp803_rails(const void *fdt) { int node; bool dc1sw = false; /* locate the PMIC DT node, bail out if not found */ node = fdt_node_offset_by_compatible(fdt, -1, "x-powers,axp803"); if (node == -FDT_ERR_NOTFOUND) { WARN("BL31: PMIC: No AXP803 DT node, skipping initial setup.\n"); return; } if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) { axp_clrbits(0x8f, BIT(4)); axp_setbits(0x30, BIT(2)); INFO("PMIC: AXP803: Enabling DRIVEVBUS\n"); } /* descend into the "regulators" subnode */ node = fdt_first_subnode(fdt, node); /* iterate over all regulators to find used ones */ for (node = fdt_first_subnode(fdt, node); node != -FDT_ERR_NOTFOUND; node = fdt_next_subnode(fdt, node)) { struct axp_regulator *reg; const char *name; int length; /* We only care if it's always on or referenced. */ if (!should_enable_regulator(fdt, node)) continue; name = fdt_get_name(fdt, node, &length); for (reg = regulators; reg->dt_name; reg++) { if (!strncmp(name, reg->dt_name, length)) { setup_regulator(fdt, node, reg); break; } } if (!strncmp(name, "dc1sw", length)) { /* Delay DC1SW enablement to avoid overheating. */ dc1sw = true; continue; } } /* * If DLDO2 is enabled after DC1SW, the PMIC overheats and shuts * down. So always enable DC1SW as the very last regulator. */ if (dc1sw) { INFO("PMIC: AXP803: Enabling DC1SW\n"); axp_setbits(0x12, BIT(7)); } }
void dump_fdt(const void *fdt) { int err; dprintf("FDT @ %p:\n", fdt); if (!fdt) return; err = fdt_check_header(fdt); if (err) { dprintf("fdt error: %s\n", fdt_strerror(err)); return; } dprintf("fdt_totalsize: %d\n", fdt_totalsize(fdt)); dprintf("fdt_off_dt_struct: %d\n", fdt_off_dt_struct(fdt)); dprintf("fdt_off_dt_strings: %d\n", fdt_off_dt_strings(fdt)); dprintf("fdt_off_mem_rsvmap: %d\n", fdt_off_mem_rsvmap(fdt)); dprintf("fdt_version: %d\n", fdt_version(fdt)); dprintf("fdt_last_comp_version: %d\n", fdt_last_comp_version(fdt)); dprintf("fdt_boot_cpuid_phys: %d\n", fdt_boot_cpuid_phys(fdt)); dprintf("fdt_size_dt_strings: %d\n", fdt_size_dt_strings(fdt)); dprintf("fdt_size_dt_struct: %d\n", fdt_size_dt_struct(fdt)); #ifdef FDT_DUMP_NODES dprintf("fdt tree:\n"); int node = -1; int depth = 0; while ((node = fdt_next_node(fdt, node, &depth)) >= 0) { dprintf(DS"node at %d: '%s'\n", DA, node, fdt_get_name(fdt, node, NULL)); #ifdef FDT_DUMP_PROPS int prop, len; const struct fdt_property *property; prop = fdt_first_property_offset(fdt, node); while (prop >= 0) { property = fdt_get_property_by_offset(fdt, prop, &len); if (property == NULL) { dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); break; } dprintf(DS" prop at %d: '%s', len %d\n", DA, prop, fdt_string(fdt, fdt32_to_cpu(property->nameoff)), fdt32_to_cpu(property->len)); #ifdef FDT_DUMP_PROP_VALUES dump_hex(property->data, fdt32_to_cpu(property->len), depth); #endif prop = fdt_next_property_offset(fdt, prop); } #endif } #endif }
/* We currently assume a fixed address/size. Enforce that here. */ static void check_cells(const void *dt, int node, int address, int size) { const struct fdt_property *p; int parent; int len; int n; parent = fdt_parent_offset(dt, node); if (node < 0) { fprintf(stderr, "missing parent node for %s\n", fdt_get_name(dt, node, NULL)); exit(1); } p = fdt_get_property(dt, parent, "#address-cells", &len); if (!p || len != 4) { fprintf(stderr, "Invalid or missing #address-cells for %s\n", fdt_get_name(dt, node, NULL)); exit(1); } n = fdt32_to_cpu(*(uint32_t *)p->data); if (n != address) { fprintf(stderr, "Incorrect #address-cells for %s (expected %d got %d)\n", fdt_get_name(dt, node, NULL), address, n); exit(1); } p = fdt_get_property(dt, parent, "#size-cells", &len); if (!p || len != 4) { fprintf(stderr, "Invalid or missing #size-cells for %s\n", fdt_get_name(dt, node, NULL)); exit(1); } n = fdt32_to_cpu(*(uint32_t *)p->data); if (n != size) { fprintf(stderr, "Incorrect #size-cells for %s (expected %d got %d)\n", fdt_get_name(dt, node, NULL), size, n); exit(1); } }
/** * h_include() - Include handler function for fdt_find_regions() * * This function decides whether to include or exclude a node, property or * compatible string. The function is defined by fdt_find_regions(). * * The algorithm is documented in the code - disp->invert is 0 for normal * operation, and 1 to invert the sense of all matches. * * See */ static int h_include(void *priv, const void *fdt, int offset, int type, const char *data, int size) { struct display_info *disp = priv; int inc, len; inc = check_type_include(priv, type, data, size); if (disp->include_root && type == FDT_IS_PROP && offset == 0 && inc) return 1; /* * If the node name does not tell us anything, check the * compatible string */ if (inc == -1 && type == FDT_IS_NODE) { debug(" - checking compatible2\n"); data = fdt_getprop(fdt, offset, "compatible", &len); inc = check_type_include(priv, FDT_IS_COMPAT, data, len); } /* If we still have no idea, check for properties in the node */ if (inc != 1 && type == FDT_IS_NODE && (disp->types_inc & FDT_NODE_HAS_PROP)) { debug(" - checking node '%s'\n", fdt_get_name(fdt, offset, NULL)); for (offset = fdt_first_property_offset(fdt, offset); offset > 0 && inc != 1; offset = fdt_next_property_offset(fdt, offset)) { const struct fdt_property *prop; const char *str; prop = fdt_get_property_by_offset(fdt, offset, NULL); if (!prop) continue; str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); inc = check_type_include(priv, FDT_NODE_HAS_PROP, str, strlen(str)); } if (inc == -1) inc = 0; } switch (inc) { case 1: inc = !disp->invert; break; case 0: inc = disp->invert; break; } debug(" - returning %d\n", inc); return inc; }
static int copy_spd(struct pei_data *peid) { const int gpio_vector[] = {41, 42, 43, 10, -1}; int spd_index; const void *blob = gd->fdt_blob; int node, spd_node; int ret, i; for (i = 0; ; i++) { if (gpio_vector[i] == -1) break; ret = gpio_requestf(gpio_vector[i], "spd_id%d", i); if (ret) { debug("%s: Could not request gpio %d\n", __func__, gpio_vector[i]); return ret; } } spd_index = gpio_get_values_as_int(gpio_vector); debug("spd index %d\n", spd_index); node = fdtdec_next_compatible(blob, 0, COMPAT_MEMORY_SPD); if (node < 0) { printf("SPD data not found.\n"); return -ENOENT; } for (spd_node = fdt_first_subnode(blob, node); spd_node > 0; spd_node = fdt_next_subnode(blob, spd_node)) { const char *data; int len; if (fdtdec_get_int(blob, spd_node, "reg", -1) != spd_index) continue; data = fdt_getprop(blob, spd_node, "data", &len); if (len < sizeof(peid->spd_data[0])) { printf("Missing SPD data\n"); return -EINVAL; } debug("Using SDRAM SPD data for '%s'\n", fdt_get_name(blob, spd_node, NULL)); memcpy(peid->spd_data[0], data, sizeof(peid->spd_data[0])); break; } if (spd_node < 0) { printf("No SPD data found for index %d\n", spd_index); return -ENOENT; } return 0; }
static void prop_get_fdt(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { sPAPRDRConnector *drc = SPAPR_DR_CONNECTOR(obj); int fdt_offset_next, fdt_offset, fdt_depth; void *fdt; if (!drc->fdt) { return; } fdt = drc->fdt; fdt_offset = drc->fdt_start_offset; fdt_depth = 0; do { const char *name = NULL; const struct fdt_property *prop = NULL; int prop_len = 0, name_len = 0; uint32_t tag; tag = fdt_next_tag(fdt, fdt_offset, &fdt_offset_next); switch (tag) { case FDT_BEGIN_NODE: fdt_depth++; name = fdt_get_name(fdt, fdt_offset, &name_len); visit_start_struct(v, NULL, NULL, name, 0, NULL); break; case FDT_END_NODE: /* shouldn't ever see an FDT_END_NODE before FDT_BEGIN_NODE */ g_assert(fdt_depth > 0); visit_end_struct(v, NULL); fdt_depth--; break; case FDT_PROP: { int i; prop = fdt_get_property_by_offset(fdt, fdt_offset, &prop_len); name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); visit_start_list(v, name, NULL); for (i = 0; i < prop_len; i++) { visit_type_uint8(v, (uint8_t *)&prop->data[i], NULL, NULL); } visit_end_list(v, NULL); break; } default: error_setg(&error_abort, "device FDT in unexpected state: %d", tag); } fdt_offset = fdt_offset_next; } while (fdt_depth != 0); }
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; int offset, depth, namelen; const char *name; CHECK_HEADER(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { if (pdepth < depth) continue; /* overflowed buffer */ while (pdepth > depth) { do { p--; } while (buf[p-1] != '/'); pdepth--; } name = fdt_get_name(fdt, offset, &namelen); if (!name) return namelen; if ((p + namelen + 1) <= buflen) { memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; pdepth++; } if (offset == nodeoffset) { if (pdepth < (depth + 1)) return -FDT_ERR_NOSPACE; if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; return p; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ }
/* Add RAM. */ static void create_ram(const void *dt) { int node = -1; const struct fdt_property *p; int len; uint32_t base; uint32_t size; uint32_t *data; ram_addr_t offset; while (1) { node = fdt_node_offset_by_prop_value(dt, node, "device_type", "memory", 7); if (node < 0) break; check_cells(dt, node, 1, 1); p = fdt_get_property(dt, node, "reg", &len); if (!p || (len % 8) != 0) { fprintf(stderr, "bad memory section %s\n", fdt_get_name(dt, node, NULL)); exit(1); } data = (uint32_t *)p->data; while (len) { base = fdt32_to_cpu(data[0]); size = fdt32_to_cpu(data[1]); data += 2; len -= 8; /* Ignore zero size regions. */ if (size == 0) continue; offset = qemu_ram_alloc(size); cpu_register_physical_memory(base, size, offset | IO_MEM_RAM); devtree_ram_map_size++; devtree_ram_map = qemu_realloc(devtree_ram_map, devtree_ram_map_size * sizeof(devtree_ram_region)); devtree_ram_map[devtree_ram_map_size - 1].base = base; devtree_ram_map[devtree_ram_map_size - 1].size = size; } } /* FIXME: Merge and sort memory map entries. */ /* Technically there's no reason we have to have RAM. However in practice it indicates a busted machine description. */ if (!devtree_ram_map) { fprintf(stderr, "No memory regions found\n"); exit(1); } }
static bool_t __init device_tree_node_matches(const void *fdt, int node, const char *match) { const char *name; size_t match_len; name = fdt_get_name(fdt, node, NULL); match_len = strlen(match); /* Match both "match" and "match@..." patterns but not "match-foo". */ return strncmp(name, match, match_len) == 0 && (name[match_len] == '@' || name[match_len] == '\0'); }
int i2c_chip_ofdata_to_platdata(const void *blob, int node, struct dm_i2c_chip *chip) { chip->offset_len = 1; /* default */ chip->flags = 0; chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1); if (chip->chip_addr == -1) { debug("%s: I2C Node '%s' has no 'reg' property\n", __func__, fdt_get_name(blob, node, NULL)); return -EINVAL; } return 0; }
int cros_ec_decode_ec_flash(const void *blob, struct fdt_cros_ec *config) { int flash_node, node; node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC); if (node < 0) { debug("Failed to find chrome-ec node'\n"); return -1; } flash_node = fdt_subnode_offset(blob, node, "flash"); if (flash_node < 0) { debug("Failed to find flash node\n"); return -1; } if (fdtdec_read_fmap_entry(blob, flash_node, "flash", &config->flash)) { debug("Failed to decode flash node in chrome-ec'\n"); return -1; } config->flash_erase_value = fdtdec_get_int(blob, flash_node, "erase-value", -1); for (node = fdt_first_subnode(blob, flash_node); node >= 0; node = fdt_next_subnode(blob, node)) { const char *name = fdt_get_name(blob, node, NULL); enum ec_flash_region region; if (0 == strcmp(name, "ro")) { region = EC_FLASH_REGION_RO; } else if (0 == strcmp(name, "rw")) { region = EC_FLASH_REGION_RW; } else if (0 == strcmp(name, "wp-ro")) { region = EC_FLASH_REGION_WP_RO; } else { debug("Unknown EC flash region name '%s'\n", name); return -1; } if (fdtdec_read_fmap_entry(blob, node, "reg", &config->region[region])) { debug("Failed to decode flash region in chrome-ec'\n"); return -1; } } return 0; }
int lists_bind_fdt(struct udevice *parent, const void *blob, int offset) { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); struct driver *entry; struct udevice *dev; const char *name; int result = 0; int ret; dm_dbg("bind node %s\n", fdt_get_name(blob, offset, NULL)); for (entry = driver; entry != driver + n_ents; entry++) { ret = driver_check_compatible(blob, offset, entry->of_match); if (ret == -ENOENT) { continue; } else if (ret == -ENODEV) { break; } else if (ret) { dm_warn("Device tree error at offset %d\n", offset); if (!result || ret != -ENOENT) result = ret; break; } name = fdt_get_name(blob, offset, NULL); dm_dbg(" - found match at '%s'\n", entry->name); ret = device_bind(parent, entry, name, NULL, offset, &dev); if (ret) { dm_warn("No match for driver '%s'\n", entry->name); if (!result || ret != -ENOENT) result = ret; } } return result; }
static int list_subnodes(const void *blob, int node) { int nextoffset; /* */ uint32_t tag; /* */ int level = 0; /* */ const char *pathp; int depth = 1; /* */ while (level >= 0) { tag = fdt_next_tag(blob, node, &nextoffset); switch (tag) { case FDT_BEGIN_NODE: pathp = fdt_get_name(blob, node, NULL); if (level <= depth) { if (pathp == NULL) pathp = "/* NULL pointer error */"; if (*pathp == '\0') pathp = "/"; /* */ if (level == 1) puts(pathp); } level++; if (level >= MAX_LEVEL) { printf("Nested too deep, aborting.\n"); return 1; } break; case FDT_END_NODE: level--; if (level == 0) level = -1; /* */ break; case FDT_END: return 1; case FDT_PROP: break; default: if (level <= depth) printf("Unknown tag 0x%08X\n", tag); return 1; } node = nextoffset; } return 0; }
/* Get the value of a property of a package. */ static ssize_t ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, size_t buflen) { const void *prop; const char *name; int len, offset; uint32_t cpuid; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); prop = fdt_getprop(fdtp, offset, propname, &len); if (prop == NULL && strcmp(propname, "name") == 0) { /* Emulate the 'name' property */ name = fdt_get_name(fdtp, offset, &len); strncpy(buf, name, buflen); if (len + 1 > buflen) len = buflen; return (len + 1); } if (prop == NULL && offset == fdt_path_offset(fdtp, "/chosen")) { if (strcmp(propname, "fdtbootcpu") == 0) { cpuid = cpu_to_fdt32(fdt_boot_cpuid_phys(fdtp)); len = sizeof(cpuid); prop = &cpuid; } if (strcmp(propname, "fdtmemreserv") == 0) { prop = (char *)fdtp + fdt_off_mem_rsvmap(fdtp); len = sizeof(uint64_t)*2*fdt_num_mem_rsv(fdtp); } } if (prop == NULL) return (-1); if (len > buflen) len = buflen; bcopy(prop, buf, len); return (len); }
int fdtdec_get_alias_seq(const void *blob, const char *base, int offset, int *seqp) { int base_len = strlen(base); const char *find_name; int find_namelen; int prop_offset; int aliases; find_name = fdt_get_name(blob, offset, &find_namelen); debug("Looking for '%s' at %d, name %s\n", base, offset, find_name); aliases = fdt_path_offset(blob, "/aliases"); for (prop_offset = fdt_first_property_offset(blob, aliases); prop_offset > 0; prop_offset = fdt_next_property_offset(blob, prop_offset)) { const char *prop; const char *name; const char *slash; const char *p; int len; prop = fdt_getprop_by_offset(blob, prop_offset, &name, &len); debug(" - %s, %s\n", name, prop); if (len < find_namelen || *prop != '/' || prop[len - 1] || strncmp(name, base, base_len)) continue; slash = strrchr(prop, '/'); if (strcmp(slash + 1, find_name)) continue; for (p = name + strlen(name) - 1; p > name; p--) { if (!isdigit(*p)) { *seqp = simple_strtoul(p + 1, NULL, 10); debug("Found seq %d\n", *seqp); return 0; } } } debug("Not found\n"); return -ENOENT; }
/*** * sandbox_read_state_nodes() - Read state associated with a driver * * This looks through all compatible nodes and calls the read function on * each one, to read in the state. * * If nothing is found, it still calls the read function once, to set up a * single global state for that driver. * * @state: Sandbox state * @io: Method to use for reading state * @blob: FDT containing state * @return 0 if OK, -EINVAL if the read function returned failure */ int sandbox_read_state_nodes(struct sandbox_state *state, struct sandbox_state_io *io, const void *blob) { int count; int node; int ret; debug(" - read %s\n", io->name); if (!io->read) return 0; node = -1; count = 0; while (blob) { node = fdt_node_offset_by_compatible(blob, node, io->compat); if (node < 0) return 0; /* No more */ debug(" - read node '%s'\n", fdt_get_name(blob, node, NULL)); ret = io->read(blob, node); if (ret) { printf("Unable to read state for '%s'\n", io->compat); return -EINVAL; } count++; } /* * If we got no saved state, call the read function once without a * node, to set up the global state. */ if (count == 0) { debug(" - read global\n"); ret = io->read(NULL, -1); if (ret) { printf("Unable to read global state for '%s'\n", io->name); return -EINVAL; } } return 0; }
/** * We have a top-level GPIO device with no actual GPIOs. It has a child * device for each Exynos GPIO bank. */ static int gpio_exynos_bind(struct udevice *parent) { struct exynos_gpio_platdata *plat = parent->platdata; struct s5p_gpio_bank *bank, *base; const void *blob = gd->fdt_blob; int node; /* If this is a child device, there is nothing to do here */ if (plat) return 0; base = (struct s5p_gpio_bank *)fdtdec_get_addr(gd->fdt_blob, parent->of_offset, "reg"); for (node = fdt_first_subnode(blob, parent->of_offset), bank = base; node > 0; node = fdt_next_subnode(blob, node), bank++) { struct exynos_gpio_platdata *plat; struct udevice *dev; fdt_addr_t reg; int ret; if (!fdtdec_get_bool(blob, node, "gpio-controller")) continue; plat = calloc(1, sizeof(*plat)); if (!plat) return -ENOMEM; reg = fdtdec_get_addr(blob, node, "reg"); if (reg != FDT_ADDR_T_NONE) bank = (struct s5p_gpio_bank *)((ulong)base + reg); plat->bank = bank; plat->bank_name = fdt_get_name(blob, node, NULL); debug("dev at %p: %s\n", bank, plat->bank_name); ret = device_bind(parent, parent->driver, plat->bank_name, plat, -1, &dev); if (ret) return ret; dev->of_offset = node; } return 0; }
/** * of_scan_flat_dt - scan flattened tree blob and call callback on each. * @it: callback function * @data: context data pointer * * This function is used to scan the flattened device-tree, it is * used to extract the memory information at boot before we can * unflatten the tree */ int __init of_scan_flat_dt(int (*it)(unsigned long node, const char *uname, int depth, void *data), void *data) { const void *blob = initial_boot_params; const char *pathp; int offset, rc = 0, depth = -1; for (offset = fdt_next_node(blob, -1, &depth); offset >= 0 && depth >= 0 && !rc; offset = fdt_next_node(blob, offset, &depth)) { pathp = fdt_get_name(blob, offset, NULL); if (*pathp == '/') pathp = kbasename(pathp); rc = it(offset, pathp, depth, data); } return rc; }