mmc: fsl_esdhc: workaround for hardware 3.3v IO reliability issue
[oweals/u-boot.git] / drivers / core / of_access.c
index 93a65604967bfb0f2c74646fd13331346b8ec8e5..922e78f99b8275b812c395ef9968dfb534279baa 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Originally from Linux v4.9
  * Paul Mackerras      August 1996.
  *
  * This file follows drivers/of/base.c with functions in the same order as the
  * Linux version.
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
-#include <libfdt.h>
+#include <log.h>
+#include <malloc.h>
+#include <linux/bug.h>
+#include <linux/libfdt.h>
 #include <dm/of_access.h>
 #include <linux/ctype.h>
 #include <linux/err.h>
@@ -96,6 +98,30 @@ int of_n_size_cells(const struct device_node *np)
        return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
 }
 
+int of_simple_addr_cells(const struct device_node *np)
+{
+       const __be32 *ip;
+
+       ip = of_get_property(np, "#address-cells", NULL);
+       if (ip)
+               return be32_to_cpup(ip);
+
+       /* Return a default of 2 to match fdt_address_cells()*/
+       return 2;
+}
+
+int of_simple_size_cells(const struct device_node *np)
+{
+       const __be32 *ip;
+
+       ip = of_get_property(np, "#size-cells", NULL);
+       if (ip)
+               return be32_to_cpup(ip);
+
+       /* Return a default of 2 to match fdt_size_cells()*/
+       return 2;
+}
+
 struct property *of_find_property(const struct device_node *np,
                                  const char *name, int *lenp)
 {
@@ -147,6 +173,38 @@ const void *of_get_property(const struct device_node *np, const char *name,
        return pp ? pp->value : NULL;
 }
 
+const struct property *of_get_first_property(const struct device_node *np)
+{
+       if (!np)
+               return NULL;
+
+       return  np->properties;
+}
+
+const struct property *of_get_next_property(const struct device_node *np,
+                                           const struct property *property)
+{
+       if (!np)
+               return NULL;
+
+       return property->next;
+}
+
+const void *of_get_property_by_prop(const struct device_node *np,
+                                   const struct property *property,
+                                   const char **name,
+                                   int *lenp)
+{
+       if (!np || !property)
+               return NULL;
+       if (name)
+               *name = property->name;
+       if (lenp)
+               *lenp = property->length;
+
+       return property->value;
+}
+
 static const char *of_prop_next_string(struct property *prop, const char *cur)
 {
        const void *curv = cur;
@@ -353,6 +411,33 @@ struct device_node *of_find_compatible_node(struct device_node *from,
        return np;
 }
 
+static int of_device_has_prop_value(const struct device_node *device,
+                                   const char *propname, const void *propval,
+                                   int proplen)
+{
+       struct property *prop = of_find_property(device, propname, NULL);
+
+       if (!prop || !prop->value || prop->length != proplen)
+               return 0;
+       return !memcmp(prop->value, propval, proplen);
+}
+
+struct device_node *of_find_node_by_prop_value(struct device_node *from,
+                                              const char *propname,
+                                              const void *propval, int proplen)
+{
+       struct device_node *np;
+
+       for_each_of_allnodes_from(from, np) {
+               if (of_device_has_prop_value(np, propname, propval, proplen) &&
+                   of_node_get(np))
+                       break;
+       }
+       of_node_put(from);
+
+       return np;
+}
+
 struct device_node *of_find_node_by_phandle(phandle handle)
 {
        struct device_node *np;
@@ -397,39 +482,67 @@ static void *of_find_property_value_of_size(const struct device_node *np,
 }
 
 int of_read_u32(const struct device_node *np, const char *propname, u32 *outp)
+{
+       return of_read_u32_index(np, propname, 0, outp);
+}
+
+int of_read_u32_array(const struct device_node *np, const char *propname,
+                     u32 *out_values, size_t sz)
+{
+       const __be32 *val;
+
+       debug("%s: %s: ", __func__, propname);
+       val = of_find_property_value_of_size(np, propname,
+                                            sz * sizeof(*out_values));
+
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+
+       debug("size %zd\n", sz);
+       while (sz--)
+               *out_values++ = be32_to_cpup(val++);
+
+       return 0;
+}
+
+int of_read_u32_index(const struct device_node *np, const char *propname,
+                     int index, u32 *outp)
 {
        const __be32 *val;
 
        debug("%s: %s: ", __func__, propname);
        if (!np)
                return -EINVAL;
-       val = of_find_property_value_of_size(np, propname, sizeof(*outp));
+
+       val = of_find_property_value_of_size(np, propname,
+                                            sizeof(*outp) * (index + 1));
        if (IS_ERR(val)) {
                debug("(not found)\n");
                return PTR_ERR(val);
        }
 
-       *outp = be32_to_cpup(val);
+       *outp = be32_to_cpup(val + index);
        debug("%#x (%d)\n", *outp, *outp);
 
        return 0;
 }
 
-int of_read_u32_array(const struct device_node *np, const char *propname,
-                     u32 *out_values, size_t sz)
+int of_read_u64(const struct device_node *np, const char *propname, u64 *outp)
 {
-       const __be32 *val;
+       const __be64 *val;
 
        debug("%s: %s: ", __func__, propname);
-       val = of_find_property_value_of_size(np, propname,
-                                            sz * sizeof(*out_values));
-
-       if (IS_ERR(val))
+       if (!np)
+               return -EINVAL;
+       val = of_find_property_value_of_size(np, propname, sizeof(*outp));
+       if (IS_ERR(val)) {
+               debug("(not found)\n");
                return PTR_ERR(val);
+       }
 
-       debug("size %zd\n", sz);
-       while (sz--)
-               *out_values++ = be32_to_cpup(val++);
+       *outp = be64_to_cpup(val);
+       debug("%#llx (%lld)\n", (unsigned long long)*outp,
+              (unsigned long long)*outp);
 
        return 0;
 }
@@ -506,7 +619,7 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
 {
        const __be32 *list, *list_end;
        int rc = 0, cur_index = 0;
-       uint32_t count = 0;
+       uint32_t count;
        struct device_node *node = NULL;
        phandle phandle;
        int size;
@@ -641,6 +754,13 @@ int of_parse_phandle_with_args(const struct device_node *np,
                                            index, out_args);
 }
 
+int of_count_phandle_with_args(const struct device_node *np,
+                              const char *list_name, const char *cells_name)
+{
+       return __of_parse_phandle_with_args(np, list_name, cells_name, 0,
+                                           -1, NULL);
+}
+
 static void of_alias_add(struct alias_prop *ap, struct device_node *np,
                         int id, const char *stem, int stem_len)
 {
@@ -735,6 +855,24 @@ int of_alias_get_id(const struct device_node *np, const char *stem)
        return id;
 }
 
+int of_alias_get_highest_id(const char *stem)
+{
+       struct alias_prop *app;
+       int id = -1;
+
+       mutex_lock(&of_mutex);
+       list_for_each_entry(app, &aliases_lookup, link) {
+               if (strcmp(app->stem, stem) != 0)
+                       continue;
+
+               if (app->id > id)
+                       id = app->id;
+       }
+       mutex_unlock(&of_mutex);
+
+       return id;
+}
+
 struct device_node *of_get_stdout(void)
 {
        return of_stdout;