mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	dm: core: Allow uclass to set up a device's child before it is probed
Some buses need to set up their devices before they can be used. This setup may well be common to all buses in a particular uclass. Support a common pre-probe method for the uclass, called before any bus devices are probed. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 | ||||
|  * | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user