+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2017 Google, Inc
* Written by Simon Glass <sjg@chromium.org>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <fdt_support.h>
-#include <libfdt.h>
+#include <linux/libfdt.h>
#include <dm/of_access.h>
#include <dm/of_addr.h>
#include <dm/ofnode.h>
return def;
}
+int ofnode_read_u64(ofnode node, const char *propname, u64 *outp)
+{
+ const fdt64_t *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u64(ofnode_to_np(node), propname, outp);
+
+ cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
+ &len);
+ if (!cell || len < sizeof(*cell)) {
+ debug("(not found)\n");
+ return -EINVAL;
+ }
+ *outp = fdt64_to_cpu(cell[0]);
+ debug("%#llx (%lld)\n", (unsigned long long)*outp,
+ (unsigned long long)*outp);
+
+ return 0;
+}
+
+int ofnode_read_u64_default(ofnode node, const char *propname, u64 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u64(node, propname, &def);
+
+ return def;
+}
+
bool ofnode_read_bool(ofnode node, const char *propname)
{
const void *prop;
fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
}
+ofnode ofnode_get_parent(ofnode node)
+{
+ ofnode parent;
+
+ assert(ofnode_valid(node));
+ if (ofnode_is_np(node))
+ parent = np_to_ofnode(of_get_parent(ofnode_to_np(node)));
+ else
+ parent.of_offset = fdt_parent_offset(gd->fdt_blob,
+ ofnode_to_offset(node));
+
+ return parent;
+}
+
const char *ofnode_get_name(ofnode node)
{
assert(ofnode_valid(node));
return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
}
+ofnode ofnode_get_by_phandle(uint phandle)
+{
+ ofnode node;
+
+ if (of_live_active())
+ node = np_to_ofnode(of_find_node_by_phandle(phandle));
+ else
+ node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
+ phandle);
+
+ return node;
+}
+
int ofnode_read_size(ofnode node, const char *propname)
{
int len;
fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
{
+ int na, ns;
+ fdt_size_t size;
+
if (ofnode_is_np(node)) {
const __be32 *prop_val;
uint flags;
- u64 size;
- int na;
- prop_val = of_get_address(ofnode_to_np(node), index, &size,
- &flags);
+ prop_val = of_get_address(ofnode_to_np(node), index,
+ (u64 *)&size, &flags);
if (!prop_val)
return FDT_ADDR_T_NONE;
- na = of_n_addr_cells(ofnode_to_np(node));
- return of_read_number(prop_val, na);
+
+ ns = of_n_size_cells(ofnode_to_np(node));
+
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) {
+ return of_translate_address(ofnode_to_np(node), prop_val);
+ } else {
+ na = of_n_addr_cells(ofnode_to_np(node));
+ return of_read_number(prop_val, na);
+ }
} else {
- return fdt_get_base_address(gd->fdt_blob,
- ofnode_to_offset(node));
+ na = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+ ns = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+ return fdtdec_get_addr_size_fixed(gd->fdt_blob,
+ ofnode_to_offset(node), "reg",
+ index, na, ns, &size, true);
}
return FDT_ADDR_T_NONE;
int ret;
ret = of_parse_phandle_with_args(ofnode_to_np(node),
- list_name, cells_name, index, &args);
+ list_name, cells_name, index,
+ &args);
if (ret)
return ret;
ofnode_from_of_phandle_args(&args, out_args);
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
- ofnode_to_offset(node), list_name, cells_name,
- cell_count, index, &args);
+ ofnode_to_offset(node),
+ list_name, cells_name,
+ cell_count, index, &args);
if (ret)
return ret;
ofnode_from_fdtdec_phandle_args(&args, out_args);
if (!ofnode_valid(timings))
return -EINVAL;
- for (i = 0, node = ofnode_first_subnode(timings);
- ofnode_valid(node) && i != index;
- node = ofnode_first_subnode(node))
- i++;
+ i = 0;
+ ofnode_for_each_subnode(node, timings) {
+ if (i++ == index)
+ break;
+ }
if (!ofnode_valid(node))
return -EINVAL;
int na, ns;
int psize;
const struct device_node *np = ofnode_to_np(node);
- const __be32 *prop = of_get_property(np, "reg", &psize);
+ const __be32 *prop = of_get_property(np, property, &psize);
+ if (!prop)
+ return FDT_ADDR_T_NONE;
na = of_n_addr_cells(np);
- ns = of_n_addr_cells(np);
+ ns = of_n_size_cells(np);
*sizep = of_read_number(prop + na, ns);
- return of_read_number(prop, na);
+
+ if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0)
+ return of_translate_address(np, prop);
+ else
+ return of_read_number(prop, na);
} else {
return fdtdec_get_addr_size(gd->fdt_blob,
ofnode_to_offset(node), property,
addr->phys_mid = fdt32_to_cpu(cell[1]);
addr->phys_lo = fdt32_to_cpu(cell[1]);
break;
- } else {
- cell += (FDT_PCI_ADDR_CELLS +
- FDT_PCI_SIZE_CELLS);
}
+
+ cell += (FDT_PCI_ADDR_CELLS +
+ FDT_PCI_SIZE_CELLS);
}
if (i == num) {
}
return 0;
- } else {
- ret = -EINVAL;
}
+ ret = -EINVAL;
+
fail:
debug("(not found)\n");
return ret;
}
+int ofnode_read_pci_vendev(ofnode node, u16 *vendor, u16 *device)
+{
+ const char *list, *end;
+ int len;
+
+ list = ofnode_get_property(node, "compatible", &len);
+ if (!list)
+ return -ENOENT;
+
+ end = list + len;
+ while (list < end) {
+ len = strlen(list);
+ if (len >= strlen("pciVVVV,DDDD")) {
+ char *s = strstr(list, "pci");
+
+ /*
+ * check if the string is something like pciVVVV,DDDD.RR
+ * or just pciVVVV,DDDD
+ */
+ if (s && s[7] == ',' &&
+ (s[12] == '.' || s[12] == 0)) {
+ s += 3;
+ *vendor = simple_strtol(s, NULL, 16);
+
+ s += 5;
+ *device = simple_strtol(s, NULL, 16);
+
+ return 0;
+ }
+ }
+ list += (len + 1);
+ }
+
+ return -ENOENT;
+}
+
int ofnode_read_addr_cells(ofnode node)
{
if (ofnode_is_np(node))
{
if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
return true;
+ if (ofnode_read_bool(node, "u-boot,dm-pre-proper"))
+ return true;
#ifdef CONFIG_TPL_BUILD
if (ofnode_read_bool(node, "u-boot,dm-tpl"))
return ofnode_read_resource(node, index, res);
}
+
+u64 ofnode_translate_address(ofnode node, const fdt32_t *in_addr)
+{
+ if (ofnode_is_np(node))
+ return of_translate_address(ofnode_to_np(node), in_addr);
+ else
+ return fdt_translate_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+}
+
+int ofnode_device_is_compatible(ofnode node, const char *compat)
+{
+ if (ofnode_is_np(node))
+ return of_device_is_compatible(ofnode_to_np(node), compat,
+ NULL, NULL);
+ else
+ return !fdt_node_check_compatible(gd->fdt_blob,
+ ofnode_to_offset(node),
+ compat);
+}
+
+ofnode ofnode_by_compatible(ofnode from, const char *compat)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(of_find_compatible_node(
+ (struct device_node *)ofnode_to_np(from), NULL,
+ compat));
+ } else {
+ return offset_to_ofnode(fdt_node_offset_by_compatible(
+ gd->fdt_blob, ofnode_to_offset(from), compat));
+ }
+}
+
+ofnode ofnode_by_prop_value(ofnode from, const char *propname,
+ const void *propval, int proplen)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(of_find_node_by_prop_value(
+ (struct device_node *)ofnode_to_np(from), propname,
+ propval, proplen));
+ } else {
+ return offset_to_ofnode(fdt_node_offset_by_prop_value(
+ gd->fdt_blob, ofnode_to_offset(from),
+ propname, propval, proplen));
+ }
+}
+
+int ofnode_write_prop(ofnode node, const char *propname, int len,
+ const void *value)
+{
+ const struct device_node *np = ofnode_to_np(node);
+ struct property *pp;
+ struct property *pp_last = NULL;
+ struct property *new;
+
+ if (!of_live_active())
+ return -ENOSYS;
+
+ if (!np)
+ return -EINVAL;
+
+ for (pp = np->properties; pp; pp = pp->next) {
+ if (strcmp(pp->name, propname) == 0) {
+ /* Property exists -> change value */
+ pp->value = (void *)value;
+ pp->length = len;
+ return 0;
+ }
+ pp_last = pp;
+ }
+
+ if (!pp_last)
+ return -ENOENT;
+
+ /* Property does not exist -> append new property */
+ new = malloc(sizeof(struct property));
+ if (!new)
+ return -ENOMEM;
+
+ new->name = strdup(propname);
+ if (!new->name) {
+ free(new);
+ return -ENOMEM;
+ }
+
+ new->value = (void *)value;
+ new->length = len;
+ new->next = NULL;
+
+ pp_last->next = new;
+
+ return 0;
+}
+
+int ofnode_write_string(ofnode node, const char *propname, const char *value)
+{
+ if (!of_live_active())
+ return -ENOSYS;
+
+ assert(ofnode_valid(node));
+
+ debug("%s: %s = %s", __func__, propname, value);
+
+ return ofnode_write_prop(node, propname, strlen(value) + 1, value);
+}
+
+int ofnode_set_enabled(ofnode node, bool value)
+{
+ if (!of_live_active())
+ return -ENOSYS;
+
+ assert(ofnode_valid(node));
+
+ if (value)
+ return ofnode_write_string(node, "status", "okay");
+ else
+ return ofnode_write_string(node, "status", "disable");
+}