xref: /openbmc/u-boot/test/dm/bus.c (revision 1d6edcbf)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
21ca7e206SSimon Glass /*
31ca7e206SSimon Glass  * Copyright (c) 2014 Google, Inc
41ca7e206SSimon Glass  */
51ca7e206SSimon Glass 
61ca7e206SSimon Glass #include <common.h>
79f8037eaSSimon Glass #ifdef CONFIG_SANDBOX
89f8037eaSSimon Glass #include <os.h>
99f8037eaSSimon Glass #endif
101ca7e206SSimon Glass #include <dm.h>
11e59f458dSSimon Glass #include <dm/device-internal.h>
121ca7e206SSimon Glass #include <dm/test.h>
13cdc133bdSSimon Glass #include <dm/uclass-internal.h>
141ca7e206SSimon Glass #include <dm/util.h>
15e721b882SJoe Hershberger #include <test/ut.h>
161ca7e206SSimon Glass 
171ca7e206SSimon Glass DECLARE_GLOBAL_DATA_PTR;
181ca7e206SSimon Glass 
19cdc133bdSSimon Glass struct dm_test_parent_platdata {
20cdc133bdSSimon Glass 	int count;
210118ce79SSimon Glass 	int bind_flag;
22081f2fcbSSimon Glass 	int uclass_bind_flag;
23cdc133bdSSimon Glass };
24cdc133bdSSimon Glass 
25a327dee0SSimon Glass enum {
26a327dee0SSimon Glass 	FLAG_CHILD_PROBED	= 10,
27a327dee0SSimon Glass 	FLAG_CHILD_REMOVED	= -7,
28a327dee0SSimon Glass };
29a327dee0SSimon Glass 
30a327dee0SSimon Glass static struct dm_test_state *test_state;
31a327dee0SSimon Glass 
testbus_drv_probe(struct udevice * dev)321ca7e206SSimon Glass static int testbus_drv_probe(struct udevice *dev)
331ca7e206SSimon Glass {
342e3f1ff6SSimon Glass 	return dm_scan_fdt_dev(dev);
351ca7e206SSimon Glass }
361ca7e206SSimon Glass 
testbus_child_post_bind(struct udevice * dev)370118ce79SSimon Glass static int testbus_child_post_bind(struct udevice *dev)
380118ce79SSimon Glass {
390118ce79SSimon Glass 	struct dm_test_parent_platdata *plat;
400118ce79SSimon Glass 
410118ce79SSimon Glass 	plat = dev_get_parent_platdata(dev);
420118ce79SSimon Glass 	plat->bind_flag = 1;
43081f2fcbSSimon Glass 	plat->uclass_bind_flag = 2;
440118ce79SSimon Glass 
450118ce79SSimon Glass 	return 0;
460118ce79SSimon Glass }
470118ce79SSimon Glass 
testbus_child_pre_probe(struct udevice * dev)48a327dee0SSimon Glass static int testbus_child_pre_probe(struct udevice *dev)
49a327dee0SSimon Glass {
50bcbe3d15SSimon Glass 	struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
51a327dee0SSimon Glass 
52a327dee0SSimon Glass 	parent_data->flag += FLAG_CHILD_PROBED;
53a327dee0SSimon Glass 
54a327dee0SSimon Glass 	return 0;
55a327dee0SSimon Glass }
56a327dee0SSimon Glass 
testbus_child_pre_probe_uclass(struct udevice * dev)5783c7e434SSimon Glass static int testbus_child_pre_probe_uclass(struct udevice *dev)
5883c7e434SSimon Glass {
5983c7e434SSimon Glass 	struct dm_test_priv *priv = dev_get_priv(dev);
6083c7e434SSimon Glass 
6183c7e434SSimon Glass 	priv->uclass_flag++;
6283c7e434SSimon Glass 
6383c7e434SSimon Glass 	return 0;
6483c7e434SSimon Glass }
6583c7e434SSimon Glass 
testbus_child_post_probe_uclass(struct udevice * dev)66*d92878aaSBin Meng static int testbus_child_post_probe_uclass(struct udevice *dev)
67*d92878aaSBin Meng {
68*d92878aaSBin Meng 	struct dm_test_priv *priv = dev_get_priv(dev);
69*d92878aaSBin Meng 
70*d92878aaSBin Meng 	priv->uclass_postp++;
71*d92878aaSBin Meng 
72*d92878aaSBin Meng 	return 0;
73*d92878aaSBin Meng }
74*d92878aaSBin Meng 
testbus_child_post_remove(struct udevice * dev)75a327dee0SSimon Glass static int testbus_child_post_remove(struct udevice *dev)
76a327dee0SSimon Glass {
77bcbe3d15SSimon Glass 	struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
78a327dee0SSimon Glass 	struct dm_test_state *dms = test_state;
79a327dee0SSimon Glass 
80a327dee0SSimon Glass 	parent_data->flag += FLAG_CHILD_REMOVED;
81a327dee0SSimon Glass 	if (dms)
82a327dee0SSimon Glass 		dms->removed = dev;
83a327dee0SSimon Glass 
84a327dee0SSimon Glass 	return 0;
85a327dee0SSimon Glass }
86a327dee0SSimon Glass 
871ca7e206SSimon Glass static const struct udevice_id testbus_ids[] = {
881ca7e206SSimon Glass 	{
891ca7e206SSimon Glass 		.compatible = "denx,u-boot-test-bus",
901ca7e206SSimon Glass 		.data = DM_TEST_TYPE_FIRST },
911ca7e206SSimon Glass 	{ }
921ca7e206SSimon Glass };
931ca7e206SSimon Glass 
941ca7e206SSimon Glass U_BOOT_DRIVER(testbus_drv) = {
951ca7e206SSimon Glass 	.name	= "testbus_drv",
961ca7e206SSimon Glass 	.of_match	= testbus_ids,
971ca7e206SSimon Glass 	.id	= UCLASS_TEST_BUS,
981ca7e206SSimon Glass 	.probe	= testbus_drv_probe,
990118ce79SSimon Glass 	.child_post_bind = testbus_child_post_bind,
1001ca7e206SSimon Glass 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
1011ca7e206SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
102e59f458dSSimon Glass 	.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
103cdc133bdSSimon Glass 	.per_child_platdata_auto_alloc_size =
104cdc133bdSSimon Glass 			sizeof(struct dm_test_parent_platdata),
105a327dee0SSimon Glass 	.child_pre_probe = testbus_child_pre_probe,
106a327dee0SSimon Glass 	.child_post_remove = testbus_child_post_remove,
1071ca7e206SSimon Glass };
1081ca7e206SSimon Glass 
1091ca7e206SSimon Glass UCLASS_DRIVER(testbus) = {
1101ca7e206SSimon Glass 	.name		= "testbus",
1111ca7e206SSimon Glass 	.id		= UCLASS_TEST_BUS,
1129cc36a2bSSimon Glass 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
11383c7e434SSimon Glass 	.child_pre_probe = testbus_child_pre_probe_uclass,
114*d92878aaSBin Meng 	.child_post_probe = testbus_child_post_probe_uclass,
1151ca7e206SSimon Glass };
1161ca7e206SSimon Glass 
1171ca7e206SSimon Glass /* Test that we can probe for children */
dm_test_bus_children(struct unit_test_state * uts)118e721b882SJoe Hershberger static int dm_test_bus_children(struct unit_test_state *uts)
1191ca7e206SSimon Glass {
1202786cd74SBin Meng 	int num_devices = 8;
1211ca7e206SSimon Glass 	struct udevice *bus;
1221ca7e206SSimon Glass 	struct uclass *uc;
1231ca7e206SSimon Glass 
1241ca7e206SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
1251ca7e206SSimon Glass 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
1261ca7e206SSimon Glass 
1271ca7e206SSimon Glass 	/* Probe the bus, which should yield 3 more devices */
1281ca7e206SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
1291ca7e206SSimon Glass 	num_devices += 3;
1301ca7e206SSimon Glass 
1311ca7e206SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
1321ca7e206SSimon Glass 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
1331ca7e206SSimon Glass 
134e721b882SJoe Hershberger 	ut_assert(!dm_check_devices(uts, num_devices));
1351ca7e206SSimon Glass 
1361ca7e206SSimon Glass 	return 0;
1371ca7e206SSimon Glass }
1381ca7e206SSimon Glass DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
139997c87bbSSimon Glass 
140997c87bbSSimon Glass /* Test our functions for accessing children */
dm_test_bus_children_funcs(struct unit_test_state * uts)141e721b882SJoe Hershberger static int dm_test_bus_children_funcs(struct unit_test_state *uts)
142997c87bbSSimon Glass {
143997c87bbSSimon Glass 	const void *blob = gd->fdt_blob;
144997c87bbSSimon Glass 	struct udevice *bus, *dev;
145997c87bbSSimon Glass 	int node;
146997c87bbSSimon Glass 
147997c87bbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
148997c87bbSSimon Glass 
149997c87bbSSimon Glass 	/* device_get_child() */
150997c87bbSSimon Glass 	ut_assertok(device_get_child(bus, 0, &dev));
151997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
152997c87bbSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 5, &dev));
153997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
154997c87bbSSimon Glass 	ut_asserteq_str("c-test@5", dev->name);
155997c87bbSSimon Glass 
156997c87bbSSimon Glass 	/* Device with sequence number 0 should be accessible */
157997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
158997c87bbSSimon Glass 	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
159997c87bbSSimon Glass 	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
160997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
161997c87bbSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
162997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
163997c87bbSSimon Glass 
164997c87bbSSimon Glass 	/* There is no device with sequence number 2 */
165997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
166997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
167997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
168997c87bbSSimon Glass 
169997c87bbSSimon Glass 	/* Looking for something that is not a child */
170997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/junk");
171997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
172997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/d-test");
173997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
174997c87bbSSimon Glass 
175298afb52SSimon Glass 	return 0;
176298afb52SSimon Glass }
177298afb52SSimon Glass DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
178298afb52SSimon Glass 
dm_test_bus_children_of_offset(struct unit_test_state * uts)179298afb52SSimon Glass static int dm_test_bus_children_of_offset(struct unit_test_state *uts)
180298afb52SSimon Glass {
181298afb52SSimon Glass 	const void *blob = gd->fdt_blob;
182298afb52SSimon Glass 	struct udevice *bus, *dev;
183298afb52SSimon Glass 	int node;
184298afb52SSimon Glass 
185298afb52SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
1864f414d39SSimon Glass 	ut_assertnonnull(bus);
187298afb52SSimon Glass 
188997c87bbSSimon Glass 	/* Find a valid child */
189997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/some-bus/c-test@1");
190298afb52SSimon Glass 	ut_assert(node > 0);
191997c87bbSSimon Glass 	ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
1924f414d39SSimon Glass 	ut_assertnonnull(dev);
193997c87bbSSimon Glass 	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
194997c87bbSSimon Glass 	ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
1954f414d39SSimon Glass 	ut_assertnonnull(dev);
196997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
197997c87bbSSimon Glass 
198997c87bbSSimon Glass 	return 0;
199997c87bbSSimon Glass }
200298afb52SSimon Glass DM_TEST(dm_test_bus_children_of_offset,
201298afb52SSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
202e59f458dSSimon Glass 
203a8981d4fSSimon Glass /* Test that we can iterate through children */
dm_test_bus_children_iterators(struct unit_test_state * uts)204e721b882SJoe Hershberger static int dm_test_bus_children_iterators(struct unit_test_state *uts)
205a8981d4fSSimon Glass {
206a8981d4fSSimon Glass 	struct udevice *bus, *dev, *child;
207a8981d4fSSimon Glass 
208a8981d4fSSimon Glass 	/* Walk through the children one by one */
209a8981d4fSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
210a8981d4fSSimon Glass 	ut_assertok(device_find_first_child(bus, &dev));
211a8981d4fSSimon Glass 	ut_asserteq_str("c-test@5", dev->name);
212a8981d4fSSimon Glass 	ut_assertok(device_find_next_child(&dev));
213a8981d4fSSimon Glass 	ut_asserteq_str("c-test@0", dev->name);
214a8981d4fSSimon Glass 	ut_assertok(device_find_next_child(&dev));
215a8981d4fSSimon Glass 	ut_asserteq_str("c-test@1", dev->name);
216a8981d4fSSimon Glass 	ut_assertok(device_find_next_child(&dev));
217a8981d4fSSimon Glass 	ut_asserteq_ptr(dev, NULL);
218a8981d4fSSimon Glass 
219a8981d4fSSimon Glass 	/* Move to the next child without using device_find_first_child() */
220a8981d4fSSimon Glass 	ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
221a8981d4fSSimon Glass 	ut_asserteq_str("c-test@5", dev->name);
222a8981d4fSSimon Glass 	ut_assertok(device_find_next_child(&dev));
223a8981d4fSSimon Glass 	ut_asserteq_str("c-test@0", dev->name);
224a8981d4fSSimon Glass 
225a8981d4fSSimon Glass 	/* Try a device with no children */
226a8981d4fSSimon Glass 	ut_assertok(device_find_first_child(dev, &child));
227a8981d4fSSimon Glass 	ut_asserteq_ptr(child, NULL);
228a8981d4fSSimon Glass 
229a8981d4fSSimon Glass 	return 0;
230a8981d4fSSimon Glass }
231a8981d4fSSimon Glass DM_TEST(dm_test_bus_children_iterators,
232a8981d4fSSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
233a8981d4fSSimon Glass 
234e59f458dSSimon Glass /* Test that the bus can store data about each child */
test_bus_parent_data(struct unit_test_state * uts)235e721b882SJoe Hershberger static int test_bus_parent_data(struct unit_test_state *uts)
236e59f458dSSimon Glass {
237e59f458dSSimon Glass 	struct dm_test_parent_data *parent_data;
238e59f458dSSimon Glass 	struct udevice *bus, *dev;
239e59f458dSSimon Glass 	struct uclass *uc;
240e59f458dSSimon Glass 	int value;
241e59f458dSSimon Glass 
242e59f458dSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
243e59f458dSSimon Glass 
244e59f458dSSimon Glass 	/* Check that parent data is allocated */
245e59f458dSSimon Glass 	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
246bcbe3d15SSimon Glass 	ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
247e59f458dSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
248bcbe3d15SSimon Glass 	parent_data = dev_get_parent_priv(dev);
249e59f458dSSimon Glass 	ut_assert(NULL != parent_data);
250e59f458dSSimon Glass 
251e59f458dSSimon Glass 	/* Check that it starts at 0 and goes away when device is removed */
252e59f458dSSimon Glass 	parent_data->sum += 5;
253e59f458dSSimon Glass 	ut_asserteq(5, parent_data->sum);
254706865afSStefan Roese 	device_remove(dev, DM_REMOVE_NORMAL);
255bcbe3d15SSimon Glass 	ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
256e59f458dSSimon Glass 
257e59f458dSSimon Glass 	/* Check that we can do this twice */
258e59f458dSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
259bcbe3d15SSimon Glass 	parent_data = dev_get_parent_priv(dev);
260e59f458dSSimon Glass 	ut_assert(NULL != parent_data);
261e59f458dSSimon Glass 	parent_data->sum += 5;
262e59f458dSSimon Glass 	ut_asserteq(5, parent_data->sum);
263e59f458dSSimon Glass 
264e59f458dSSimon Glass 	/* Add parent data to all children */
265e59f458dSSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
266e59f458dSSimon Glass 	value = 5;
267e59f458dSSimon Glass 	uclass_foreach_dev(dev, uc) {
268e59f458dSSimon Glass 		/* Ignore these if they are not on this bus */
269e59f458dSSimon Glass 		if (dev->parent != bus) {
270bcbe3d15SSimon Glass 			ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
271e59f458dSSimon Glass 			continue;
272e59f458dSSimon Glass 		}
273e59f458dSSimon Glass 		ut_assertok(device_probe(dev));
274bcbe3d15SSimon Glass 		parent_data = dev_get_parent_priv(dev);
275e59f458dSSimon Glass 
276e59f458dSSimon Glass 		parent_data->sum = value;
277e59f458dSSimon Glass 		value += 5;
278e59f458dSSimon Glass 	}
279e59f458dSSimon Glass 
280e59f458dSSimon Glass 	/* Check it is still there */
281e59f458dSSimon Glass 	value = 5;
282e59f458dSSimon Glass 	uclass_foreach_dev(dev, uc) {
283e59f458dSSimon Glass 		/* Ignore these if they are not on this bus */
284e59f458dSSimon Glass 		if (dev->parent != bus)
285e59f458dSSimon Glass 			continue;
286bcbe3d15SSimon Glass 		parent_data = dev_get_parent_priv(dev);
287e59f458dSSimon Glass 
288e59f458dSSimon Glass 		ut_asserteq(value, parent_data->sum);
289e59f458dSSimon Glass 		value += 5;
290e59f458dSSimon Glass 	}
291e59f458dSSimon Glass 
292e59f458dSSimon Glass 	return 0;
293e59f458dSSimon Glass }
294dac8db2cSSimon Glass /* Test that the bus can store data about each child */
dm_test_bus_parent_data(struct unit_test_state * uts)295e721b882SJoe Hershberger static int dm_test_bus_parent_data(struct unit_test_state *uts)
296dac8db2cSSimon Glass {
297e721b882SJoe Hershberger 	return test_bus_parent_data(uts);
298dac8db2cSSimon Glass }
299e59f458dSSimon Glass DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
300a327dee0SSimon Glass 
301dac8db2cSSimon Glass /* As above but the size is controlled by the uclass */
dm_test_bus_parent_data_uclass(struct unit_test_state * uts)302e721b882SJoe Hershberger static int dm_test_bus_parent_data_uclass(struct unit_test_state *uts)
303dac8db2cSSimon Glass {
304e23eb614SSimon Glass 	struct driver *drv;
305dac8db2cSSimon Glass 	struct udevice *bus;
306dac8db2cSSimon Glass 	int size;
307dac8db2cSSimon Glass 	int ret;
308dac8db2cSSimon Glass 
309dac8db2cSSimon Glass 	/* Set the driver size to 0 so that the uclass size is used */
310dac8db2cSSimon Glass 	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
311e23eb614SSimon Glass 	drv = (struct driver *)bus->driver;
312e23eb614SSimon Glass 	size = drv->per_child_auto_alloc_size;
3139f8037eaSSimon Glass 
3149f8037eaSSimon Glass #ifdef CONFIG_SANDBOX
3159f8037eaSSimon Glass 	os_mprotect_allow(bus->uclass->uc_drv, sizeof(*bus->uclass->uc_drv));
3169f8037eaSSimon Glass 	os_mprotect_allow(drv, sizeof(*drv));
3179f8037eaSSimon Glass #endif
318dac8db2cSSimon Glass 	bus->uclass->uc_drv->per_child_auto_alloc_size = size;
319e23eb614SSimon Glass 	drv->per_child_auto_alloc_size = 0;
320e721b882SJoe Hershberger 	ret = test_bus_parent_data(uts);
321dac8db2cSSimon Glass 	if (ret)
322dac8db2cSSimon Glass 		return ret;
323dac8db2cSSimon Glass 	bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
324e23eb614SSimon Glass 	drv->per_child_auto_alloc_size = size;
325dac8db2cSSimon Glass 
326dac8db2cSSimon Glass 	return 0;
327dac8db2cSSimon Glass }
328dac8db2cSSimon Glass DM_TEST(dm_test_bus_parent_data_uclass,
329dac8db2cSSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
330dac8db2cSSimon Glass 
331a327dee0SSimon Glass /* Test that the bus ops are called when a child is probed/removed */
dm_test_bus_parent_ops(struct unit_test_state * uts)332e721b882SJoe Hershberger static int dm_test_bus_parent_ops(struct unit_test_state *uts)
333a327dee0SSimon Glass {
334a327dee0SSimon Glass 	struct dm_test_parent_data *parent_data;
335e721b882SJoe Hershberger 	struct dm_test_state *dms = uts->priv;
336a327dee0SSimon Glass 	struct udevice *bus, *dev;
337a327dee0SSimon Glass 	struct uclass *uc;
338a327dee0SSimon Glass 
339a327dee0SSimon Glass 	test_state = dms;
340a327dee0SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
341a327dee0SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
342a327dee0SSimon Glass 
343a327dee0SSimon Glass 	uclass_foreach_dev(dev, uc) {
344a327dee0SSimon Glass 		/* Ignore these if they are not on this bus */
345a327dee0SSimon Glass 		if (dev->parent != bus)
346a327dee0SSimon Glass 			continue;
347bcbe3d15SSimon Glass 		ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
348a327dee0SSimon Glass 
349a327dee0SSimon Glass 		ut_assertok(device_probe(dev));
350bcbe3d15SSimon Glass 		parent_data = dev_get_parent_priv(dev);
351a327dee0SSimon Glass 		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
352a327dee0SSimon Glass 	}
353a327dee0SSimon Glass 
354a327dee0SSimon Glass 	uclass_foreach_dev(dev, uc) {
355a327dee0SSimon Glass 		/* Ignore these if they are not on this bus */
356a327dee0SSimon Glass 		if (dev->parent != bus)
357a327dee0SSimon Glass 			continue;
358bcbe3d15SSimon Glass 		parent_data = dev_get_parent_priv(dev);
359a327dee0SSimon Glass 		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
360706865afSStefan Roese 		ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
361bcbe3d15SSimon Glass 		ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
362a327dee0SSimon Glass 		ut_asserteq_ptr(dms->removed, dev);
363a327dee0SSimon Glass 	}
364a327dee0SSimon Glass 	test_state = NULL;
365a327dee0SSimon Glass 
366a327dee0SSimon Glass 	return 0;
367a327dee0SSimon Glass }
368a327dee0SSimon Glass DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
369cdc133bdSSimon Glass 
test_bus_parent_platdata(struct unit_test_state * uts)370e721b882SJoe Hershberger static int test_bus_parent_platdata(struct unit_test_state *uts)
371cdc133bdSSimon Glass {
372cdc133bdSSimon Glass 	struct dm_test_parent_platdata *plat;
373cdc133bdSSimon Glass 	struct udevice *bus, *dev;
374cdc133bdSSimon Glass 	int child_count;
375cdc133bdSSimon Glass 
376cdc133bdSSimon Glass 	/* Check that the bus has no children */
377cdc133bdSSimon Glass 	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
378cdc133bdSSimon Glass 	device_find_first_child(bus, &dev);
379cdc133bdSSimon Glass 	ut_asserteq_ptr(NULL, dev);
380cdc133bdSSimon Glass 
381cdc133bdSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
382cdc133bdSSimon Glass 
383cdc133bdSSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
384cdc133bdSSimon Glass 	     dev;
385cdc133bdSSimon Glass 	     device_find_next_child(&dev)) {
386cdc133bdSSimon Glass 		/* Check that platform data is allocated */
387cdc133bdSSimon Glass 		plat = dev_get_parent_platdata(dev);
388cdc133bdSSimon Glass 		ut_assert(plat != NULL);
389cdc133bdSSimon Glass 
390cdc133bdSSimon Glass 		/*
391cdc133bdSSimon Glass 		 * Check that it is not affected by the device being
392cdc133bdSSimon Glass 		 * probed/removed
393cdc133bdSSimon Glass 		 */
394cdc133bdSSimon Glass 		plat->count++;
395cdc133bdSSimon Glass 		ut_asserteq(1, plat->count);
396cdc133bdSSimon Glass 		device_probe(dev);
397706865afSStefan Roese 		device_remove(dev, DM_REMOVE_NORMAL);
398cdc133bdSSimon Glass 
399cdc133bdSSimon Glass 		ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
400cdc133bdSSimon Glass 		ut_asserteq(1, plat->count);
401cdc133bdSSimon Glass 		ut_assertok(device_probe(dev));
402cdc133bdSSimon Glass 		child_count++;
403cdc133bdSSimon Glass 	}
404cdc133bdSSimon Glass 	ut_asserteq(3, child_count);
405cdc133bdSSimon Glass 
406cdc133bdSSimon Glass 	/* Removing the bus should also have no effect (it is still bound) */
407706865afSStefan Roese 	device_remove(bus, DM_REMOVE_NORMAL);
408cdc133bdSSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
409cdc133bdSSimon Glass 	     dev;
410cdc133bdSSimon Glass 	     device_find_next_child(&dev)) {
411cdc133bdSSimon Glass 		/* Check that platform data is allocated */
412cdc133bdSSimon Glass 		plat = dev_get_parent_platdata(dev);
413cdc133bdSSimon Glass 		ut_assert(plat != NULL);
414cdc133bdSSimon Glass 		ut_asserteq(1, plat->count);
415cdc133bdSSimon Glass 		child_count++;
416cdc133bdSSimon Glass 	}
417cdc133bdSSimon Glass 	ut_asserteq(3, child_count);
418cdc133bdSSimon Glass 
419cdc133bdSSimon Glass 	/* Unbind all the children */
420cdc133bdSSimon Glass 	do {
421cdc133bdSSimon Glass 		device_find_first_child(bus, &dev);
422cdc133bdSSimon Glass 		if (dev)
423cdc133bdSSimon Glass 			device_unbind(dev);
424cdc133bdSSimon Glass 	} while (dev);
425cdc133bdSSimon Glass 
426cdc133bdSSimon Glass 	/* Now the child platdata should be removed and re-added */
427cdc133bdSSimon Glass 	device_probe(bus);
428cdc133bdSSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
429cdc133bdSSimon Glass 	     dev;
430cdc133bdSSimon Glass 	     device_find_next_child(&dev)) {
431cdc133bdSSimon Glass 		/* Check that platform data is allocated */
432cdc133bdSSimon Glass 		plat = dev_get_parent_platdata(dev);
433cdc133bdSSimon Glass 		ut_assert(plat != NULL);
434cdc133bdSSimon Glass 		ut_asserteq(0, plat->count);
435cdc133bdSSimon Glass 		child_count++;
436cdc133bdSSimon Glass 	}
437cdc133bdSSimon Glass 	ut_asserteq(3, child_count);
438cdc133bdSSimon Glass 
439cdc133bdSSimon Glass 	return 0;
440cdc133bdSSimon Glass }
441ba8da9dcSSimon Glass 
442ba8da9dcSSimon Glass /* Test that the bus can store platform data about each child */
dm_test_bus_parent_platdata(struct unit_test_state * uts)443e721b882SJoe Hershberger static int dm_test_bus_parent_platdata(struct unit_test_state *uts)
444ba8da9dcSSimon Glass {
445e721b882SJoe Hershberger 	return test_bus_parent_platdata(uts);
446ba8da9dcSSimon Glass }
447cdc133bdSSimon Glass DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
448ba8da9dcSSimon Glass 
449ba8da9dcSSimon Glass /* As above but the size is controlled by the uclass */
dm_test_bus_parent_platdata_uclass(struct unit_test_state * uts)450e721b882SJoe Hershberger static int dm_test_bus_parent_platdata_uclass(struct unit_test_state *uts)
451ba8da9dcSSimon Glass {
452ba8da9dcSSimon Glass 	struct udevice *bus;
453e23eb614SSimon Glass 	struct driver *drv;
454ba8da9dcSSimon Glass 	int size;
455ba8da9dcSSimon Glass 	int ret;
456ba8da9dcSSimon Glass 
457ba8da9dcSSimon Glass 	/* Set the driver size to 0 so that the uclass size is used */
458ba8da9dcSSimon Glass 	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
459e23eb614SSimon Glass 	drv = (struct driver *)bus->driver;
460e23eb614SSimon Glass 	size = drv->per_child_platdata_auto_alloc_size;
4619f8037eaSSimon Glass #ifdef CONFIG_SANDBOX
4629f8037eaSSimon Glass 	os_mprotect_allow(bus->uclass->uc_drv, sizeof(*bus->uclass->uc_drv));
4639f8037eaSSimon Glass 	os_mprotect_allow(drv, sizeof(*drv));
4649f8037eaSSimon Glass #endif
465ba8da9dcSSimon Glass 	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
466e23eb614SSimon Glass 	drv->per_child_platdata_auto_alloc_size = 0;
467e721b882SJoe Hershberger 	ret = test_bus_parent_platdata(uts);
468ba8da9dcSSimon Glass 	if (ret)
469ba8da9dcSSimon Glass 		return ret;
470ba8da9dcSSimon Glass 	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
471e23eb614SSimon Glass 	drv->per_child_platdata_auto_alloc_size = size;
472ba8da9dcSSimon Glass 
473ba8da9dcSSimon Glass 	return 0;
474ba8da9dcSSimon Glass }
475ba8da9dcSSimon Glass DM_TEST(dm_test_bus_parent_platdata_uclass,
476ba8da9dcSSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
4770118ce79SSimon Glass 
4780118ce79SSimon Glass /* Test that the child post_bind method is called */
dm_test_bus_child_post_bind(struct unit_test_state * uts)479e721b882SJoe Hershberger static int dm_test_bus_child_post_bind(struct unit_test_state *uts)
4800118ce79SSimon Glass {
4810118ce79SSimon Glass 	struct dm_test_parent_platdata *plat;
4820118ce79SSimon Glass 	struct udevice *bus, *dev;
4830118ce79SSimon Glass 	int child_count;
4840118ce79SSimon Glass 
4850118ce79SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
4860118ce79SSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
4870118ce79SSimon Glass 	     dev;
4880118ce79SSimon Glass 	     device_find_next_child(&dev)) {
4890118ce79SSimon Glass 		/* Check that platform data is allocated */
4900118ce79SSimon Glass 		plat = dev_get_parent_platdata(dev);
4910118ce79SSimon Glass 		ut_assert(plat != NULL);
4920118ce79SSimon Glass 		ut_asserteq(1, plat->bind_flag);
4930118ce79SSimon Glass 		child_count++;
4940118ce79SSimon Glass 	}
4950118ce79SSimon Glass 	ut_asserteq(3, child_count);
4960118ce79SSimon Glass 
4970118ce79SSimon Glass 	return 0;
4980118ce79SSimon Glass }
4990118ce79SSimon Glass DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
500081f2fcbSSimon Glass 
501081f2fcbSSimon Glass /* Test that the child post_bind method is called */
dm_test_bus_child_post_bind_uclass(struct unit_test_state * uts)502e721b882SJoe Hershberger static int dm_test_bus_child_post_bind_uclass(struct unit_test_state *uts)
503081f2fcbSSimon Glass {
504081f2fcbSSimon Glass 	struct dm_test_parent_platdata *plat;
505081f2fcbSSimon Glass 	struct udevice *bus, *dev;
506081f2fcbSSimon Glass 	int child_count;
507081f2fcbSSimon Glass 
508081f2fcbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
509081f2fcbSSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
510081f2fcbSSimon Glass 	     dev;
511081f2fcbSSimon Glass 	     device_find_next_child(&dev)) {
512081f2fcbSSimon Glass 		/* Check that platform data is allocated */
513081f2fcbSSimon Glass 		plat = dev_get_parent_platdata(dev);
514081f2fcbSSimon Glass 		ut_assert(plat != NULL);
515081f2fcbSSimon Glass 		ut_asserteq(2, plat->uclass_bind_flag);
516081f2fcbSSimon Glass 		child_count++;
517081f2fcbSSimon Glass 	}
518081f2fcbSSimon Glass 	ut_asserteq(3, child_count);
519081f2fcbSSimon Glass 
520081f2fcbSSimon Glass 	return 0;
521081f2fcbSSimon Glass }
522081f2fcbSSimon Glass DM_TEST(dm_test_bus_child_post_bind_uclass,
523081f2fcbSSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
52483c7e434SSimon Glass 
52583c7e434SSimon Glass /*
52683c7e434SSimon Glass  * Test that the bus' uclass' child_pre_probe() is called before the
52783c7e434SSimon Glass  * device's probe() method
52883c7e434SSimon Glass  */
dm_test_bus_child_pre_probe_uclass(struct unit_test_state * uts)529e721b882SJoe Hershberger static int dm_test_bus_child_pre_probe_uclass(struct unit_test_state *uts)
53083c7e434SSimon Glass {
53183c7e434SSimon Glass 	struct udevice *bus, *dev;
53283c7e434SSimon Glass 	int child_count;
53383c7e434SSimon Glass 
53483c7e434SSimon Glass 	/*
53583c7e434SSimon Glass 	 * See testfdt_drv_probe() which effectively checks that the uclass
53683c7e434SSimon Glass 	 * flag is set before that method is called
53783c7e434SSimon Glass 	 */
53883c7e434SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
53983c7e434SSimon Glass 	for (device_find_first_child(bus, &dev), child_count = 0;
54083c7e434SSimon Glass 	     dev;
54183c7e434SSimon Glass 	     device_find_next_child(&dev)) {
54283c7e434SSimon Glass 		struct dm_test_priv *priv = dev_get_priv(dev);
54383c7e434SSimon Glass 
54483c7e434SSimon Glass 		/* Check that things happened in the right order */
54583c7e434SSimon Glass 		ut_asserteq_ptr(NULL, priv);
54683c7e434SSimon Glass 		ut_assertok(device_probe(dev));
54783c7e434SSimon Glass 
54883c7e434SSimon Glass 		priv = dev_get_priv(dev);
54983c7e434SSimon Glass 		ut_assert(priv != NULL);
55083c7e434SSimon Glass 		ut_asserteq(1, priv->uclass_flag);
55183c7e434SSimon Glass 		ut_asserteq(1, priv->uclass_total);
55283c7e434SSimon Glass 		child_count++;
55383c7e434SSimon Glass 	}
55483c7e434SSimon Glass 	ut_asserteq(3, child_count);
55583c7e434SSimon Glass 
55683c7e434SSimon Glass 	return 0;
55783c7e434SSimon Glass }
55883c7e434SSimon Glass DM_TEST(dm_test_bus_child_pre_probe_uclass,
55983c7e434SSimon Glass 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
560*d92878aaSBin Meng 
561*d92878aaSBin Meng /*
562*d92878aaSBin Meng  * Test that the bus' uclass' child_post_probe() is called after the
563*d92878aaSBin Meng  * device's probe() method
564*d92878aaSBin Meng  */
dm_test_bus_child_post_probe_uclass(struct unit_test_state * uts)565*d92878aaSBin Meng static int dm_test_bus_child_post_probe_uclass(struct unit_test_state *uts)
566*d92878aaSBin Meng {
567*d92878aaSBin Meng 	struct udevice *bus, *dev;
568*d92878aaSBin Meng 	int child_count;
569*d92878aaSBin Meng 
570*d92878aaSBin Meng 	/*
571*d92878aaSBin Meng 	 * See testfdt_drv_probe() which effectively initializes that
572*d92878aaSBin Meng 	 * the uclass postp flag is set to a value
573*d92878aaSBin Meng 	 */
574*d92878aaSBin Meng 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
575*d92878aaSBin Meng 	for (device_find_first_child(bus, &dev), child_count = 0;
576*d92878aaSBin Meng 	     dev;
577*d92878aaSBin Meng 	     device_find_next_child(&dev)) {
578*d92878aaSBin Meng 		struct dm_test_priv *priv = dev_get_priv(dev);
579*d92878aaSBin Meng 
580*d92878aaSBin Meng 		/* Check that things happened in the right order */
581*d92878aaSBin Meng 		ut_asserteq_ptr(NULL, priv);
582*d92878aaSBin Meng 		ut_assertok(device_probe(dev));
583*d92878aaSBin Meng 
584*d92878aaSBin Meng 		priv = dev_get_priv(dev);
585*d92878aaSBin Meng 		ut_assert(priv != NULL);
586*d92878aaSBin Meng 		ut_asserteq(0, priv->uclass_postp);
587*d92878aaSBin Meng 		child_count++;
588*d92878aaSBin Meng 	}
589*d92878aaSBin Meng 	ut_asserteq(3, child_count);
590*d92878aaSBin Meng 
591*d92878aaSBin Meng 	return 0;
592*d92878aaSBin Meng }
593*d92878aaSBin Meng DM_TEST(dm_test_bus_child_post_probe_uclass,
594*d92878aaSBin Meng 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
595