diff --git a/drivers/core/device.c b/drivers/core/device.c
index 78bc460d35fb014158f9b2ba88abfdfac3bef5d7..b73d3b8961de337c1ec871d3d4ed2c1b24285e59 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -227,6 +227,10 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
 	}
 	dev->seq = seq;
 
+	ret = uclass_pre_probe_child(dev);
+	if (ret)
+		goto fail;
+
 	if (dev->parent && dev->parent->driver->child_pre_probe) {
 		ret = dev->parent->driver->child_pre_probe(dev);
 		if (ret)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index a5445518f570d72ff11fcdfa6465f82eab188435..289a5d2d53dfc7af75c19cc1dcc21aa88e8cd0cf 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -391,6 +391,19 @@ int uclass_resolve_seq(struct udevice *dev)
 	return seq;
 }
 
+int uclass_pre_probe_child(struct udevice *dev)
+{
+	struct uclass_driver *uc_drv;
+
+	if (!dev->parent)
+		return 0;
+	uc_drv = dev->parent->uclass->uc_drv;
+	if (uc_drv->child_pre_probe)
+		return uc_drv->child_pre_probe(dev);
+
+	return 0;
+}
+
 int uclass_post_probe_device(struct udevice *dev)
 {
 	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
diff --git a/include/dm/test.h b/include/dm/test.h
index f08c05da8147725f87900da81bf8944ff1c46ebc..707c69e07f02c488f10de559185769829534e689 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -67,6 +67,8 @@ enum {
 struct dm_test_priv {
 	int ping_total;
 	int op_count[DM_TEST_OP_COUNT];
+	int uclass_flag;
+	int uclass_total;
 };
 
 /**
@@ -88,6 +90,7 @@ struct dm_test_uclass_priv {
  *
  * @sum: Test value used to check parent data works correctly
  * @flag: Used to track calling of parent operations
+ * @uclass_flag: Used to track calling of parent operations by uclass
  */
 struct dm_test_parent_data {
 	int sum;
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index f718f37affba344713f7599692f9fa79b2286652..f2f254a8259736f9d24ba18ad95ba9e126eb53c2 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -43,6 +43,17 @@ int uclass_bind_device(struct udevice *dev);
  */
 int uclass_unbind_device(struct udevice *dev);
 
+/**
+ * uclass_pre_probe_child() - Deal with a child that is about to be probed
+ *
+ * Perform any pre-processing that is needed by the uclass before it can be
+ * probed.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_probe_child(struct udevice *dev);
+
 /**
  * uclass_post_probe_device() - Deal with a device that has just been probed
  *
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 5c5b8f4208387b2db92a9ce681b3e0588a1e0947..d6c40c60dda0913c27c46ffb8538176a7d595210 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -83,6 +83,7 @@ struct uclass_driver {
 	int (*post_probe)(struct udevice *dev);
 	int (*pre_remove)(struct udevice *dev);
 	int (*child_post_bind)(struct udevice *dev);
+	int (*child_pre_probe)(struct udevice *dev);
 	int (*init)(struct uclass *class);
 	int (*destroy)(struct uclass *class);
 	int priv_auto_alloc_size;
diff --git a/test/dm/bus.c b/test/dm/bus.c
index c123ed7931092e77fc7470767d53a953c4341080..faffe6a385b6f8ef9ee066ac705d959993232226 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -53,6 +53,15 @@ static int testbus_child_pre_probe(struct udevice *dev)
 	return 0;
 }
 
+static int testbus_child_pre_probe_uclass(struct udevice *dev)
+{
+	struct dm_test_priv *priv = dev_get_priv(dev);
+
+	priv->uclass_flag++;
+
+	return 0;
+}
+
 static int testbus_child_post_remove(struct udevice *dev)
 {
 	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
@@ -91,6 +100,7 @@ UCLASS_DRIVER(testbus) = {
 	.name		= "testbus",
 	.id		= UCLASS_TEST_BUS,
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.child_pre_probe = testbus_child_pre_probe_uclass,
 };
 
 /* Test that we can probe for children */
@@ -469,3 +479,39 @@ static int dm_test_bus_child_post_bind_uclass(struct dm_test_state *dms)
 }
 DM_TEST(dm_test_bus_child_post_bind_uclass,
 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/*
+ * Test that the bus' uclass' child_pre_probe() is called before the
+ * device's probe() method
+ */
+static int dm_test_bus_child_pre_probe_uclass(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	int child_count;
+
+	/*
+	 * See testfdt_drv_probe() which effectively checks that the uclass
+	 * flag is set before that method is called
+	 */
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		struct dm_test_priv *priv = dev_get_priv(dev);
+
+		/* Check that things happened in the right order */
+		ut_asserteq_ptr(NULL, priv);
+		ut_assertok(device_probe(dev));
+
+		priv = dev_get_priv(dev);
+		ut_assert(priv != NULL);
+		ut_asserteq(1, priv->uclass_flag);
+		ut_asserteq(1, priv->uclass_total);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_child_pre_probe_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index dfcb3af61bbf20e6c966a56f1abd2d1dcc412fa9..b8ee9599a22a67c999bb8cd066226cf63237f324 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -51,6 +51,13 @@ static int testfdt_drv_probe(struct udevice *dev)
 
 	priv->ping_total += DM_TEST_START_TOTAL;
 
+	/*
+	 * If this device is on a bus, the uclass_flag will be set before
+	 * calling this function. This is used by
+	 * dm_test_bus_child_pre_probe_uclass().
+	 */
+	priv->uclass_total += priv->uclass_flag;
+
 	return 0;
 }