dm: core: Add a way to read platdata for all child devices
authorSimon Glass <sjg@chromium.org>
Mon, 27 Jan 2020 15:49:47 +0000 (08:49 -0700)
committerSimon Glass <sjg@chromium.org>
Thu, 6 Feb 2020 02:33:45 +0000 (19:33 -0700)
When generating ACPI tables we need to make sure that all devices have
read their platform data, so that they can generate the tables correctly.

Rather than adding this code in ACPI, create a core function to handle it.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/core/device.c
include/dm/device.h
include/dm/read.h
test/dm/test-fdt.c

index b7f59fcde3405972d28dc4cb69030644d1823414..c948d8dbbc8908e1b16822b1bf23b6e4234ae898 100644 (file)
@@ -792,6 +792,42 @@ int device_find_child_by_name(const struct udevice *parent, const char *name,
        return -ENODEV;
 }
 
+int device_first_child_ofdata_err(struct udevice *parent, struct udevice **devp)
+{
+       struct udevice *dev;
+       int ret;
+
+       device_find_first_child(parent, &dev);
+       if (!dev)
+               return -ENODEV;
+
+       ret = device_ofdata_to_platdata(dev);
+       if (ret)
+               return ret;
+
+       *devp = dev;
+
+       return 0;
+}
+
+int device_next_child_ofdata_err(struct udevice **devp)
+{
+       struct udevice *dev = *devp;
+       int ret;
+
+       device_find_next_child(&dev);
+       if (!dev)
+               return -ENODEV;
+
+       ret = device_ofdata_to_platdata(dev);
+       if (ret)
+               return ret;
+
+       *devp = dev;
+
+       return 0;
+}
+
 struct udevice *dev_get_parent(const struct udevice *child)
 {
        return child->parent;
index 611fc2e1973ab2afc85b6f519c8a396292f9a103..2618952336cdc8222b13823cb9d225840aad2d23 100644 (file)
@@ -577,6 +577,31 @@ int device_find_first_child_by_uclass(const struct udevice *parent,
 int device_find_child_by_name(const struct udevice *parent, const char *name,
                              struct udevice **devp);
 
+/**
+ * device_first_child_ofdata_err() - Find the first child and reads its platdata
+ *
+ * The ofdata_to_platdata() method is called on the child before it is returned,
+ * but the child is not probed.
+ *
+ * @parent: Parent to check
+ * @devp: Returns child that was found, if any
+ * @return 0 on success, -ENODEV if no children, other -ve on error
+ */
+int device_first_child_ofdata_err(struct udevice *parent,
+                                 struct udevice **devp);
+
+/*
+ * device_next_child_ofdata_err() - Find the next child and read its platdata
+ *
+ * The ofdata_to_platdata() method is called on the child before it is returned,
+ * but the child is not probed.
+ *
+ * @devp: On entry, points to the previous child; on exit returns the child that
+ *     was found, if any
+ * @return 0 on success, -ENODEV if no children, other -ve on error
+ */
+int device_next_child_ofdata_err(struct udevice **devp);
+
 /**
  * device_has_children() - check if a device has any children
  *
@@ -706,6 +731,23 @@ static inline bool device_is_on_pci_bus(const struct udevice *dev)
 #define device_foreach_child(pos, parent)      \
        list_for_each_entry(pos, &parent->child_head, sibling_node)
 
+/**
+ * device_foreach_child_ofdata_to_platdata() - iterate through children
+ *
+ * This stops when it gets an error, with @pos set to the device that failed to
+ * read ofdata.
+
+ * This creates a for() loop which works through the available children of
+ * a device in order from start to end. Device ofdata is read by calling
+ * device_ofdata_to_platdata() on each one. The devices are not probed.
+ *
+ * @pos: struct udevice * for the current device
+ * @parent: parent device to scan
+ */
+#define device_foreach_child_ofdata_to_platdata(pos, parent)   \
+       for (int _ret = device_first_child_ofdata_err(parent, &dev); !_ret; \
+            _ret = device_next_child_ofdata_err(&dev))
+
 /**
  * dm_scan_fdt_dev() - Bind child device in a the device tree
  *
index 92a7328fc8fac986a6ac332c6361bacc205d5603..da8c7f25e7ca08421fe4f4d13cc368b051ff31f1 100644 (file)
@@ -844,7 +844,8 @@ static inline ofnode dev_read_next_subnode(ofnode node)
 }
 
 static inline const uint8_t *dev_read_u8_array_ptr(const struct udevice *dev,
-                                       const char *propname, size_t sz)
+                                                  const char *propname,
+                                                  size_t sz)
 {
        return ofnode_read_u8_array_ptr(dev_ofnode(dev), propname, sz);
 }
index d59c449ce0cdd8159e731dfdf7a11851c11cb31e..8fe4425b212b95f127d2271f5585f53135170592 100644 (file)
@@ -872,3 +872,22 @@ static int dm_test_read_int(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test device_first_child_ofdata_err(), etc. */
+static int dm_test_child_ofdata(struct unit_test_state *uts)
+{
+       struct udevice *bus, *dev;
+       int count;
+
+       ut_assertok(uclass_first_device_err(UCLASS_TEST_BUS, &bus));
+       count = 0;
+       device_foreach_child_ofdata_to_platdata(dev, bus) {
+               ut_assert(dev->flags & DM_FLAG_PLATDATA_VALID);
+               ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
+               count++;
+       }
+       ut_asserteq(3, count);
+
+       return 0;
+}
+DM_TEST(dm_test_child_ofdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);