* Written by Simon Glass <sjg@chromium.org>
*/
+#define LOG_CATEGORY LOGC_DT
+
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
#include <linux/ioport.h>
#include <asm/global_data.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)
+static void *oftree_list[CONFIG_OFNODE_MULTI_TREE_MAX];
+static int oftree_count;
+
+void oftree_reset(void)
+{
+ if (gd->flags & GD_FLG_RELOC) {
+ oftree_count = 0;
+ oftree_list[oftree_count++] = (void *)gd->fdt_blob;
+ }
+}
+
+static int oftree_find(const void *fdt)
+{
+ int i;
+
+ for (i = 0; i < oftree_count; i++) {
+ if (fdt == oftree_list[i])
+ return i;
+ }
+
+ return -1;
+}
+
+static oftree oftree_ensure(void *fdt)
+{
+ oftree tree;
+ int i;
+
+ if (gd->flags & GD_FLG_RELOC) {
+ i = oftree_find(fdt);
+ if (i == -1) {
+ if (oftree_count == CONFIG_OFNODE_MULTI_TREE_MAX) {
+ log_warning("Too many registered device trees (max %d)\n",
+ CONFIG_OFNODE_MULTI_TREE_MAX);
+ return oftree_null();
+ }
+
+ /* register the new tree */
+ i = oftree_count++;
+ oftree_list[i] = fdt;
+ log_debug("oftree: registered tree %d: %p\n", i, fdt);
+ }
+ } else {
+ if (fdt != gd->fdt_blob) {
+ log_debug("Cannot only access control FDT before relocation\n");
+ return oftree_null();
+ }
+ }
+
+ tree.fdt = fdt;
+
+ return tree;
+}
+
+void *ofnode_lookup_fdt(ofnode node)
+{
+ if (gd->flags & GD_FLG_RELOC) {
+ uint i = OFTREE_TREE_ID(node.of_offset);
+
+ if (i > oftree_count) {
+ log_debug("Invalid tree ID %x\n", i);
+ return NULL;
+ }
+
+ return oftree_list[i];
+ } else {
+ return (void *)gd->fdt_blob;
+ }
+}
+
+void *ofnode_to_fdt(ofnode node)
+{
+#ifdef OF_CHECKS
+ if (of_live_active())
+ return NULL;
+#endif
+ if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && ofnode_valid(node))
+ return ofnode_lookup_fdt(node);
+
+ /* Use the control FDT by default */
+ return (void *)gd->fdt_blob;
+}
+
+/**
+ * ofnode_to_offset() - convert an ofnode to a flat DT offset
+ *
+ * This cannot be called if the reference contains a node pointer.
+ *
+ * @node: Reference containing offset (possibly invalid)
+ * Return: DT offset (can be -1)
+ */
+int ofnode_to_offset(ofnode node)
+{
+#ifdef OF_CHECKS
+ if (of_live_active())
+ return -1;
+#endif
+ if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && node.of_offset >= 0)
+ return OFTREE_OFFSET(node.of_offset);
+
+ return node.of_offset;
+}
+
+oftree oftree_from_fdt(void *fdt)
+{
+ oftree tree;
+
+ if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
+ return oftree_ensure(fdt);
+
+ tree.fdt = fdt;
+
+ return tree;
+}
+
+/**
+ * noffset_to_ofnode() - convert a DT offset to an ofnode
+ *
+ * @other_node: Node in the same tree to use as a reference
+ * @of_offset: DT offset (either valid, or -1)
+ * Return: reference to the associated DT offset
+ */
+ofnode noffset_to_ofnode(ofnode other_node, int of_offset)
+{
+ ofnode node;
+
+ if (of_live_active())
+ node.np = NULL;
+ else if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || of_offset < 0 ||
+ !ofnode_valid(other_node))
+ node.of_offset = of_offset;
+ else
+ node.of_offset = OFTREE_MAKE_NODE(other_node.of_offset,
+ of_offset);
+
+ return node;
+}
+
+#else /* !OFNODE_MULTI_TREE */
+
+static inline int oftree_find(const void *fdt)
+{
+ return 0;
+}
+
+#endif /* OFNODE_MULTI_TREE */
+
+/**
+ * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
+ *
+ * Looks up the tree and returns an ofnode with the correct of_offset (i.e.
+ * containing the tree ID).
+ *
+ * If @offset is < 0 then this returns an ofnode with that offset and no tree
+ * ID.
+ *
+ * @tree: tree to check
+ * @offset: offset within that tree (can be < 0)
+ * @return node for that offset, with the correct ID
+ */
+static ofnode ofnode_from_tree_offset(oftree tree, int offset)
+{
+ ofnode node;
+
+ if (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) && offset >= 0) {
+ int tree_id = oftree_find(tree.fdt);
+
+ if (tree_id == -1)
+ return ofnode_null();
+ node.of_offset = OFTREE_NODE(tree_id, offset);
+ } else {
+ node.of_offset = offset;
+ }
+
+ return node;
+}
+
+bool ofnode_name_eq(ofnode node, const char *name)
+{
+ const char *node_name;
+ size_t len;
+
+ assert(ofnode_valid(node));
+
+ node_name = ofnode_get_name(node);
+ len = strchrnul(node_name, '@') - node_name;
+
+ return (strlen(name) == len) && !strncmp(node_name, name, len);
+}
+
+int ofnode_read_u8(ofnode node, const char *propname, u8 *outp)
+{
+ const u8 *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u8(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 = *cell;
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+u8 ofnode_read_u8_default(ofnode node, const char *propname, u8 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u8(node, propname, &def);
+
+ return def;
+}
+
+int ofnode_read_u16(ofnode node, const char *propname, u16 *outp)
+{
+ const fdt16_t *cell;
+ int len;
+
+ assert(ofnode_valid(node));
+ debug("%s: %s: ", __func__, propname);
+
+ if (ofnode_is_np(node))
+ return of_read_u16(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 = be16_to_cpup(cell);
+ debug("%#x (%d)\n", *outp, *outp);
+
+ return 0;
+}
+
+u16 ofnode_read_u16_default(ofnode node, const char *propname, u16 def)
+{
+ assert(ofnode_valid(node));
+ ofnode_read_u16(node, propname, &def);
+
+ return def;
+}
+
int ofnode_read_u32(ofnode node, const char *propname, u32 *outp)
{
return ofnode_read_u32_index(node, propname, 0, outp);
return of_read_u32_index(ofnode_to_np(node), propname, index,
outp);
- cell = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node), propname,
- &len);
+ cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+ propname, &len);
if (!cell) {
debug("(not found)\n");
return -EINVAL;
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);
+ cell = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+ propname, &len);
if (!cell || len < sizeof(*cell)) {
debug("(not found)\n");
return -EINVAL;
len = prop->length;
}
} else {
- val = fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+ val = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
propname, &len);
}
if (!val) {
debug("%s: %s: ", __func__, subnode_name);
if (ofnode_is_np(node)) {
- const struct device_node *np = ofnode_to_np(node);
+ struct device_node *np = ofnode_to_np(node);
for (np = np->child; np; np = np->sibling) {
if (!strcmp(subnode_name, np->name))
}
subnode = np_to_ofnode(np);
} else {
- int ooffset = fdt_subnode_offset(gd->fdt_blob,
+ int ooffset = fdt_subnode_offset(ofnode_to_fdt(node),
ofnode_to_offset(node), subnode_name);
- subnode = offset_to_ofnode(ooffset);
+ subnode = noffset_to_ofnode(node, ooffset);
}
debug("%s\n", ofnode_valid(subnode) ?
ofnode_get_name(subnode) : "<none>");
return of_read_u32_array(ofnode_to_np(node), propname,
out_values, sz);
} else {
- return fdtdec_get_int_array(gd->fdt_blob,
- ofnode_to_offset(node), propname,
- out_values, sz);
+ int ret;
+
+ ret = fdtdec_get_int_array(ofnode_to_fdt(node),
+ ofnode_to_offset(node), propname,
+ out_values, sz);
+
+ /* get the error right, but space is more important in SPL */
+ if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
+ if (ret == -FDT_ERR_NOTFOUND)
+ return -EINVAL;
+ else if (ret == -FDT_ERR_BADLAYOUT)
+ return -EOVERFLOW;
+ }
+ return ret;
}
}
if (ofnode_is_np(node)) {
return of_device_is_available(ofnode_to_np(node));
} else {
- return fdtdec_get_is_enabled(gd->fdt_blob,
+ return fdtdec_get_is_enabled(ofnode_to_fdt(node),
ofnode_to_offset(node));
}
}
if (ofnode_is_np(node))
return np_to_ofnode(node.np->child);
- return offset_to_ofnode(
- fdt_first_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+ return noffset_to_ofnode(node,
+ fdt_first_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
}
ofnode ofnode_next_subnode(ofnode node)
if (ofnode_is_np(node))
return np_to_ofnode(node.np->sibling);
- return offset_to_ofnode(
- fdt_next_subnode(gd->fdt_blob, ofnode_to_offset(node)));
+ return noffset_to_ofnode(node,
+ fdt_next_subnode(ofnode_to_fdt(node), ofnode_to_offset(node)));
}
#endif /* !DM_INLINE_OFNODE */
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,
+ parent.of_offset = fdt_parent_offset(ofnode_to_fdt(node),
ofnode_to_offset(node));
return parent;
}
if (ofnode_is_np(node))
- return strrchr(node.np->full_name, '/') + 1;
+ return node.np->name;
+
+ return fdt_get_name(ofnode_to_fdt(node), ofnode_to_offset(node), NULL);
+}
+
+int ofnode_get_path(ofnode node, char *buf, int buflen)
+{
+ assert(ofnode_valid(node));
+
+ if (ofnode_is_np(node)) {
+ if (strlen(node.np->full_name) >= buflen)
+ return -ENOSPC;
- return fdt_get_name(gd->fdt_blob, ofnode_to_offset(node), NULL);
+ strcpy(buf, node.np->full_name);
+
+ return 0;
+ } else {
+ int res;
+
+ res = fdt_get_path(ofnode_to_fdt(node), ofnode_to_offset(node), buf,
+ buflen);
+ if (!res)
+ return res;
+ else if (res == -FDT_ERR_NOSPACE)
+ return -ENOSPC;
+ else
+ return -EINVAL;
+ }
}
ofnode ofnode_get_by_phandle(uint phandle)
ofnode node;
if (of_live_active())
- node = np_to_ofnode(of_find_node_by_phandle(phandle));
+ node = np_to_ofnode(of_find_node_by_phandle(NULL, phandle));
else
node.of_offset = fdt_node_offset_by_phandle(gd->fdt_blob,
phandle);
return node;
}
-fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
+ofnode oftree_get_by_phandle(oftree tree, uint phandle)
+{
+ ofnode node;
+
+ if (of_live_active())
+ node = np_to_ofnode(of_find_node_by_phandle(tree.np, phandle));
+ else
+ node = ofnode_from_tree_offset(tree,
+ fdt_node_offset_by_phandle(oftree_lookup_fdt(tree),
+ phandle));
+
+ return node;
+}
+
+static fdt_addr_t __ofnode_get_addr_size_index(ofnode node, int index,
+ fdt_size_t *size, bool translate)
{
int na, ns;
+ if (size)
+ *size = FDT_SIZE_T_NONE;
+
if (ofnode_is_np(node)) {
const __be32 *prop_val;
u64 size64;
&flags);
if (!prop_val)
return FDT_ADDR_T_NONE;
+
if (size)
*size = size64;
ns = of_n_size_cells(ofnode_to_np(node));
- if (IS_ENABLED(CONFIG_OF_TRANSLATE) &&
- (ns > 0 || gd_size_cells_0())) {
+ if (translate && 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));
} else {
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,
+ return fdtdec_get_addr_size_fixed(ofnode_to_fdt(node),
ofnode_to_offset(node), "reg",
- index, na, ns, size, true);
+ index, na, ns, size,
+ translate);
}
+}
- return FDT_ADDR_T_NONE;
+fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
+{
+ return __ofnode_get_addr_size_index(node, index, size, true);
+}
+
+fdt_addr_t ofnode_get_addr_size_index_notrans(ofnode node, int index,
+ fdt_size_t *size)
+{
+ return __ofnode_get_addr_size_index(node, index, size, false);
}
fdt_addr_t ofnode_get_addr_index(ofnode node, int index)
return ofnode_get_addr_index(node, 0);
}
+fdt_size_t ofnode_get_size(ofnode node)
+{
+ fdt_size_t size;
+
+ ofnode_get_addr_size_index(node, 0, &size);
+
+ return size;
+}
+
int ofnode_stringlist_search(ofnode node, const char *property,
const char *string)
{
} else {
int ret;
- ret = fdt_stringlist_search(gd->fdt_blob,
+ ret = fdt_stringlist_search(ofnode_to_fdt(node),
ofnode_to_offset(node), property,
string);
if (ret == -FDT_ERR_NOTFOUND)
} else {
int len;
- *outp = fdt_stringlist_get(gd->fdt_blob, ofnode_to_offset(node),
+ *outp = fdt_stringlist_get(ofnode_to_fdt(node),
+ ofnode_to_offset(node),
property, index, &len);
if (len < 0)
return -EINVAL;
if (ofnode_is_np(node)) {
return of_property_count_strings(ofnode_to_np(node), property);
} else {
- return fdt_stringlist_count(gd->fdt_blob,
+ return fdt_stringlist_count(ofnode_to_fdt(node),
ofnode_to_offset(node), property);
}
}
+int ofnode_read_string_list(ofnode node, const char *property,
+ const char ***listp)
+{
+ const char **prop;
+ int count;
+ int i;
+
+ *listp = NULL;
+ count = ofnode_read_string_count(node, property);
+ if (count < 0)
+ return count;
+ if (!count)
+ return 0;
+
+ prop = calloc(count + 1, sizeof(char *));
+ if (!prop)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++)
+ ofnode_read_string_index(node, property, i, &prop[i]);
+ prop[count] = NULL;
+ *listp = prop;
+
+ return count;
+}
+
static void ofnode_from_fdtdec_phandle_args(struct fdtdec_phandle_args *in,
struct ofnode_phandle_args *out)
{
struct fdtdec_phandle_args args;
int ret;
- ret = fdtdec_parse_phandle_with_args(gd->fdt_blob,
+ ret = fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
ofnode_to_offset(node),
list_name, cells_name,
cell_count, index, &args);
return of_count_phandle_with_args(ofnode_to_np(node),
list_name, cells_name, cell_count);
else
- return fdtdec_parse_phandle_with_args(gd->fdt_blob,
+ return fdtdec_parse_phandle_with_args(ofnode_to_fdt(node),
ofnode_to_offset(node), list_name, cells_name,
cell_count, -1, NULL);
}
return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
}
+ofnode oftree_root(oftree tree)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(tree.np);
+ } else {
+ return ofnode_from_tree_offset(tree, 0);
+ }
+}
+
+ofnode oftree_path(oftree tree, const char *path)
+{
+ if (of_live_active()) {
+ return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
+ NULL));
+ } else if (*path != '/' && tree.fdt != gd->fdt_blob) {
+ return ofnode_null(); /* Aliases only on control FDT */
+ } else {
+ int offset = fdt_path_offset(tree.fdt, path);
+
+ return ofnode_from_tree_offset(tree, offset);
+ }
+}
+
const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
{
ofnode chosen_node;
if (ofnode_is_np(node))
return of_get_property(ofnode_to_np(node), propname, lenp);
else
- return fdt_getprop(gd->fdt_blob, ofnode_to_offset(node),
+ return fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node),
propname, lenp);
}
-int ofnode_get_first_property(ofnode node, struct ofprop *prop)
+int ofnode_first_property(ofnode node, struct ofprop *prop)
{
prop->node = node;
return -FDT_ERR_NOTFOUND;
} else {
prop->offset =
- fdt_first_property_offset(gd->fdt_blob,
+ fdt_first_property_offset(ofnode_to_fdt(node),
ofnode_to_offset(prop->node));
if (prop->offset < 0)
return prop->offset;
return 0;
}
-int ofnode_get_next_property(struct ofprop *prop)
+int ofnode_next_property(struct ofprop *prop)
{
if (ofnode_is_np(prop->node)) {
prop->prop = of_get_next_property(ofnode_to_np(prop->node),
if (!prop->prop)
return -FDT_ERR_NOTFOUND;
} else {
- prop->offset = fdt_next_property_offset(gd->fdt_blob,
- prop->offset);
+ prop->offset =
+ fdt_next_property_offset(ofnode_to_fdt(prop->node),
+ prop->offset);
if (prop->offset < 0)
return prop->offset;
}
return 0;
}
-const void *ofnode_get_property_by_prop(const struct ofprop *prop,
- const char **propname, int *lenp)
+const void *ofprop_get_property(const struct ofprop *prop,
+ const char **propname, int *lenp)
{
if (ofnode_is_np(prop->node))
return of_get_property_by_prop(ofnode_to_np(prop->node),
prop->prop, propname, lenp);
else
- return fdt_getprop_by_offset(gd->fdt_blob,
+ return fdt_getprop_by_offset(ofnode_to_fdt(prop->node),
prop->offset,
propname, lenp);
}
-bool ofnode_is_available(ofnode node)
-{
- if (ofnode_is_np(node))
- return of_device_is_available(ofnode_to_np(node));
- else
- return fdtdec_get_is_enabled(gd->fdt_blob,
- ofnode_to_offset(node));
-}
-
fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property,
fdt_size_t *sizep)
{
ns = of_n_size_cells(np);
*sizep = of_read_number(prop + na, ns);
- if (CONFIG_IS_ENABLED(OF_TRANSLATE) &&
- (ns > 0 || gd_size_cells_0())) {
+ if (CONFIG_IS_ENABLED(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,
+ return fdtdec_get_addr_size(ofnode_to_fdt(node),
ofnode_to_offset(node), property,
sizep);
}
return (uint8_t *)prop;
} else {
- return fdtdec_locate_byte_array(gd->fdt_blob,
+ return fdtdec_locate_byte_array(ofnode_to_fdt(node),
ofnode_to_offset(node), propname, sz);
}
}
return -ENOENT;
}
+int ofnode_read_eth_phy_id(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("ethernet-phy-idVVVV.DDDD")) {
+ char *s = strstr(list, "ethernet-phy-id");
+
+ /*
+ * check if the string is something like
+ * ethernet-phy-idVVVV.DDDD
+ */
+ if (s && s[19] == '.') {
+ s += strlen("ethernet-phy-id");
+ *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)) {
return of_n_addr_cells(ofnode_to_np(node));
} else {
- int parent = fdt_parent_offset(gd->fdt_blob,
+ int parent = fdt_parent_offset(ofnode_to_fdt(node),
ofnode_to_offset(node));
- return fdt_address_cells(gd->fdt_blob, parent);
+ return fdt_address_cells(ofnode_to_fdt(node), parent);
}
}
if (ofnode_is_np(node)) {
return of_n_size_cells(ofnode_to_np(node));
} else {
- int parent = fdt_parent_offset(gd->fdt_blob,
+ int parent = fdt_parent_offset(ofnode_to_fdt(node),
ofnode_to_offset(node));
- return fdt_size_cells(gd->fdt_blob, parent);
+ return fdt_size_cells(ofnode_to_fdt(node), parent);
}
}
if (ofnode_is_np(node))
return of_simple_addr_cells(ofnode_to_np(node));
else
- return fdt_address_cells(gd->fdt_blob, ofnode_to_offset(node));
+ return fdt_address_cells(ofnode_to_fdt(node),
+ ofnode_to_offset(node));
}
int ofnode_read_simple_size_cells(ofnode node)
if (ofnode_is_np(node))
return of_simple_size_cells(ofnode_to_np(node));
else
- return fdt_size_cells(gd->fdt_blob, ofnode_to_offset(node));
+ return fdt_size_cells(ofnode_to_fdt(node),
+ ofnode_to_offset(node));
}
bool ofnode_pre_reloc(ofnode node)
struct fdt_resource fres;
int ret;
- ret = fdt_get_resource(gd->fdt_blob, ofnode_to_offset(node),
+ ret = fdt_get_resource(ofnode_to_fdt(node),
+ ofnode_to_offset(node),
"reg", index, &fres);
if (ret < 0)
return -EINVAL;
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);
+ return fdt_translate_address(ofnode_to_fdt(node),
+ ofnode_to_offset(node), in_addr);
}
u64 ofnode_translate_dma_address(ofnode node, const fdt32_t *in_addr)
if (ofnode_is_np(node))
return of_translate_dma_address(ofnode_to_np(node), in_addr);
else
- return fdt_translate_dma_address(gd->fdt_blob, ofnode_to_offset(node), in_addr);
+ return fdt_translate_dma_address(ofnode_to_fdt(node),
+ ofnode_to_offset(node), in_addr);
}
int ofnode_get_dma_range(ofnode node, phys_addr_t *cpu, dma_addr_t *bus, u64 *size)
if (ofnode_is_np(node))
return of_get_dma_range(ofnode_to_np(node), cpu, bus, size);
else
- return fdt_get_dma_range(gd->fdt_blob, ofnode_to_offset(node),
+ return fdt_get_dma_range(ofnode_to_fdt(node),
+ ofnode_to_offset(node),
cpu, bus, size);
}
return of_device_is_compatible(ofnode_to_np(node), compat,
NULL, NULL);
else
- return !fdt_node_check_compatible(gd->fdt_blob,
+ return !fdt_node_check_compatible(ofnode_to_fdt(node),
ofnode_to_offset(node),
compat);
}
(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));
+ return noffset_to_ofnode(from,
+ fdt_node_offset_by_compatible(ofnode_to_fdt(from),
+ ofnode_to_offset(from), compat));
}
}
(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));
+ return noffset_to_ofnode(from,
+ fdt_node_offset_by_prop_value(ofnode_to_fdt(from),
+ ofnode_to_offset(from), propname, propval,
+ proplen));
}
}
-int ofnode_write_prop(ofnode node, const char *propname, int len,
- const void *value)
+int ofnode_write_prop(ofnode node, const char *propname, const void *value,
+ int len, bool copy)
{
- 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;
+ if (of_live_active()) {
+ void *newval;
+ int ret;
- 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;
+ if (copy) {
+ newval = malloc(len);
+ if (!newval)
+ return log_ret(-ENOMEM);
+ memcpy(newval, value, len);
+ value = newval;
}
- 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;
+ ret = of_write_prop(ofnode_to_np(node), propname, len, value);
+ if (ret && copy)
+ free(newval);
+ return ret;
+ } else {
+ return fdt_setprop(ofnode_to_fdt(node), ofnode_to_offset(node),
+ propname, value, len);
}
+}
- new->value = (void *)value;
- new->length = len;
- new->next = NULL;
+int ofnode_write_string(ofnode node, const char *propname, const char *value)
+{
+ assert(ofnode_valid(node));
- pp_last->next = new;
+ debug("%s: %s = %s", __func__, propname, value);
- return 0;
+ return ofnode_write_prop(node, propname, value, strlen(value) + 1,
+ false);
}
-int ofnode_write_string(ofnode node, const char *propname, const char *value)
+int ofnode_write_u32(ofnode node, const char *propname, u32 value)
{
- if (!of_live_active())
- return -ENOSYS;
+ fdt32_t *val;
assert(ofnode_valid(node));
- debug("%s: %s = %s", __func__, propname, value);
+ log_debug("%s = %x", propname, value);
+ val = malloc(sizeof(*val));
+ if (!val)
+ return -ENOMEM;
+ *val = cpu_to_fdt32(value);
- return ofnode_write_prop(node, propname, strlen(value) + 1, value);
+ return ofnode_write_prop(node, propname, val, sizeof(value), false);
}
int ofnode_set_enabled(ofnode node, bool value)
{
- if (!of_live_active())
- return -ENOSYS;
-
assert(ofnode_valid(node));
if (value)
else
return ofnode_write_string(node, "status", "disabled");
}
+
+bool ofnode_conf_read_bool(const char *prop_name)
+{
+ ofnode node;
+
+ node = ofnode_path("/config");
+ if (!ofnode_valid(node))
+ return false;
+
+ return ofnode_read_bool(node, prop_name);
+}
+
+int ofnode_conf_read_int(const char *prop_name, int default_val)
+{
+ ofnode node;
+
+ node = ofnode_path("/config");
+ if (!ofnode_valid(node))
+ return default_val;
+
+ return ofnode_read_u32_default(node, prop_name, default_val);
+}
+
+const char *ofnode_conf_read_str(const char *prop_name)
+{
+ ofnode node;
+
+ node = ofnode_path("/config");
+ if (!ofnode_valid(node))
+ return NULL;
+
+ return ofnode_read_string(node, prop_name);
+}
+
+ofnode ofnode_get_phy_node(ofnode node)
+{
+ /* DT node properties that reference a PHY node */
+ static const char * const phy_handle_str[] = {
+ "phy-handle", "phy", "phy-device",
+ };
+ struct ofnode_phandle_args args = {
+ .node = ofnode_null()
+ };
+ int i;
+
+ assert(ofnode_valid(node));
+
+ for (i = 0; i < ARRAY_SIZE(phy_handle_str); i++)
+ if (!ofnode_parse_phandle_with_args(node, phy_handle_str[i],
+ NULL, 0, 0, &args))
+ break;
+
+ return args.node;
+}
+
+phy_interface_t ofnode_read_phy_mode(ofnode node)
+{
+ const char *mode;
+ int i;
+
+ assert(ofnode_valid(node));
+
+ mode = ofnode_read_string(node, "phy-mode");
+ if (!mode)
+ mode = ofnode_read_string(node, "phy-connection-type");
+
+ if (!mode)
+ return PHY_INTERFACE_MODE_NA;
+
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++)
+ if (!strcmp(mode, phy_interface_strings[i]))
+ return i;
+
+ debug("%s: Invalid PHY interface '%s'\n", __func__, mode);
+
+ return PHY_INTERFACE_MODE_NA;
+}
+
+int ofnode_add_subnode(ofnode node, const char *name, ofnode *subnodep)
+{
+ ofnode subnode;
+ int ret = 0;
+
+ assert(ofnode_valid(node));
+
+ if (ofnode_is_np(node)) {
+ struct device_node *np, *child;
+
+ np = (struct device_node *)ofnode_to_np(node);
+ ret = of_add_subnode(np, name, -1, &child);
+ if (ret && ret != -EEXIST)
+ return ret;
+ subnode = np_to_ofnode(child);
+ } else {
+ void *fdt = ofnode_to_fdt(node);
+ int poffset = ofnode_to_offset(node);
+ int offset;
+
+ offset = fdt_add_subnode(fdt, poffset, name);
+ if (offset == -FDT_ERR_EXISTS) {
+ offset = fdt_subnode_offset(fdt, poffset, name);
+ ret = -EEXIST;
+ }
+ if (offset < 0)
+ return -EINVAL;
+ subnode = noffset_to_ofnode(node, offset);
+ }
+
+ *subnodep = subnode;
+
+ return ret; /* 0 or -EEXIST */
+}
+
+int ofnode_copy_props(ofnode src, ofnode dst)
+{
+ struct ofprop prop;
+
+ ofnode_for_each_prop(prop, src) {
+ const char *name;
+ const char *val;
+ int len, ret;
+
+ val = ofprop_get_property(&prop, &name, &len);
+ if (!val) {
+ log_debug("Cannot read prop (err=%d)\n", len);
+ return log_msg_ret("get", -EINVAL);
+ }
+ ret = ofnode_write_prop(dst, name, val, len, true);
+ if (ret) {
+ log_debug("Cannot write prop (err=%d)\n", ret);
+ return log_msg_ret("wr", -EINVAL);
+ }
+ }
+
+ return 0;
+}