xref: /rk3399_rockchip-uboot/test/dm/bus.c (revision a327dee0f40bcdebaba1a3e47f2b9f1ceb970d2a)
11ca7e206SSimon Glass /*
21ca7e206SSimon Glass  * Copyright (c) 2014 Google, Inc
31ca7e206SSimon Glass  *
41ca7e206SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
51ca7e206SSimon Glass  */
61ca7e206SSimon Glass 
71ca7e206SSimon Glass #include <common.h>
81ca7e206SSimon Glass #include <dm.h>
9e59f458dSSimon Glass #include <dm/device-internal.h>
101ca7e206SSimon Glass #include <dm/root.h>
111ca7e206SSimon Glass #include <dm/test.h>
121ca7e206SSimon Glass #include <dm/ut.h>
131ca7e206SSimon Glass #include <dm/util.h>
141ca7e206SSimon Glass 
151ca7e206SSimon Glass DECLARE_GLOBAL_DATA_PTR;
161ca7e206SSimon Glass 
17*a327dee0SSimon Glass enum {
18*a327dee0SSimon Glass 	FLAG_CHILD_PROBED	= 10,
19*a327dee0SSimon Glass 	FLAG_CHILD_REMOVED	= -7,
20*a327dee0SSimon Glass };
21*a327dee0SSimon Glass 
22*a327dee0SSimon Glass static struct dm_test_state *test_state;
23*a327dee0SSimon Glass 
241ca7e206SSimon Glass static int testbus_drv_probe(struct udevice *dev)
251ca7e206SSimon Glass {
261ca7e206SSimon Glass 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
271ca7e206SSimon Glass }
281ca7e206SSimon Glass 
29*a327dee0SSimon Glass static int testbus_child_pre_probe(struct udevice *dev)
30*a327dee0SSimon Glass {
31*a327dee0SSimon Glass 	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
32*a327dee0SSimon Glass 
33*a327dee0SSimon Glass 	parent_data->flag += FLAG_CHILD_PROBED;
34*a327dee0SSimon Glass 
35*a327dee0SSimon Glass 	return 0;
36*a327dee0SSimon Glass }
37*a327dee0SSimon Glass 
38*a327dee0SSimon Glass static int testbus_child_post_remove(struct udevice *dev)
39*a327dee0SSimon Glass {
40*a327dee0SSimon Glass 	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
41*a327dee0SSimon Glass 	struct dm_test_state *dms = test_state;
42*a327dee0SSimon Glass 
43*a327dee0SSimon Glass 	parent_data->flag += FLAG_CHILD_REMOVED;
44*a327dee0SSimon Glass 	if (dms)
45*a327dee0SSimon Glass 		dms->removed = dev;
46*a327dee0SSimon Glass 
47*a327dee0SSimon Glass 	return 0;
48*a327dee0SSimon Glass }
49*a327dee0SSimon Glass 
501ca7e206SSimon Glass static const struct udevice_id testbus_ids[] = {
511ca7e206SSimon Glass 	{
521ca7e206SSimon Glass 		.compatible = "denx,u-boot-test-bus",
531ca7e206SSimon Glass 		.data = DM_TEST_TYPE_FIRST },
541ca7e206SSimon Glass 	{ }
551ca7e206SSimon Glass };
561ca7e206SSimon Glass 
571ca7e206SSimon Glass U_BOOT_DRIVER(testbus_drv) = {
581ca7e206SSimon Glass 	.name	= "testbus_drv",
591ca7e206SSimon Glass 	.of_match	= testbus_ids,
601ca7e206SSimon Glass 	.id	= UCLASS_TEST_BUS,
611ca7e206SSimon Glass 	.probe	= testbus_drv_probe,
621ca7e206SSimon Glass 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
631ca7e206SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
64e59f458dSSimon Glass 	.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
65*a327dee0SSimon Glass 	.child_pre_probe = testbus_child_pre_probe,
66*a327dee0SSimon Glass 	.child_post_remove = testbus_child_post_remove,
671ca7e206SSimon Glass };
681ca7e206SSimon Glass 
691ca7e206SSimon Glass UCLASS_DRIVER(testbus) = {
701ca7e206SSimon Glass 	.name		= "testbus",
711ca7e206SSimon Glass 	.id		= UCLASS_TEST_BUS,
721ca7e206SSimon Glass };
731ca7e206SSimon Glass 
741ca7e206SSimon Glass /* Test that we can probe for children */
751ca7e206SSimon Glass static int dm_test_bus_children(struct dm_test_state *dms)
761ca7e206SSimon Glass {
771ca7e206SSimon Glass 	int num_devices = 4;
781ca7e206SSimon Glass 	struct udevice *bus;
791ca7e206SSimon Glass 	struct uclass *uc;
801ca7e206SSimon Glass 
811ca7e206SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
821ca7e206SSimon Glass 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
831ca7e206SSimon Glass 
841ca7e206SSimon Glass 	/* Probe the bus, which should yield 3 more devices */
851ca7e206SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
861ca7e206SSimon Glass 	num_devices += 3;
871ca7e206SSimon Glass 
881ca7e206SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
891ca7e206SSimon Glass 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
901ca7e206SSimon Glass 
911ca7e206SSimon Glass 	ut_assert(!dm_check_devices(dms, num_devices));
921ca7e206SSimon Glass 
931ca7e206SSimon Glass 	return 0;
941ca7e206SSimon Glass }
951ca7e206SSimon Glass DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
96997c87bbSSimon Glass 
97997c87bbSSimon Glass /* Test our functions for accessing children */
98997c87bbSSimon Glass static int dm_test_bus_children_funcs(struct dm_test_state *dms)
99997c87bbSSimon Glass {
100997c87bbSSimon Glass 	const void *blob = gd->fdt_blob;
101997c87bbSSimon Glass 	struct udevice *bus, *dev;
102997c87bbSSimon Glass 	int node;
103997c87bbSSimon Glass 
104997c87bbSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
105997c87bbSSimon Glass 
106997c87bbSSimon Glass 	/* device_get_child() */
107997c87bbSSimon Glass 	ut_assertok(device_get_child(bus, 0, &dev));
108997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
109997c87bbSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 5, &dev));
110997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
111997c87bbSSimon Glass 	ut_asserteq_str("c-test@5", dev->name);
112997c87bbSSimon Glass 
113997c87bbSSimon Glass 	/* Device with sequence number 0 should be accessible */
114997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
115997c87bbSSimon Glass 	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
116997c87bbSSimon Glass 	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
117997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
118997c87bbSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
119997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
120997c87bbSSimon Glass 
121997c87bbSSimon Glass 	/* There is no device with sequence number 2 */
122997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
123997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
124997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
125997c87bbSSimon Glass 
126997c87bbSSimon Glass 	/* Looking for something that is not a child */
127997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/junk");
128997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
129997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/d-test");
130997c87bbSSimon Glass 	ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
131997c87bbSSimon Glass 
132997c87bbSSimon Glass 	/* Find a valid child */
133997c87bbSSimon Glass 	node = fdt_path_offset(blob, "/some-bus/c-test@1");
134997c87bbSSimon Glass 	ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
135997c87bbSSimon Glass 	ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
136997c87bbSSimon Glass 	ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
137997c87bbSSimon Glass 	ut_assert(dev->flags & DM_FLAG_ACTIVATED);
138997c87bbSSimon Glass 
139997c87bbSSimon Glass 	return 0;
140997c87bbSSimon Glass }
141997c87bbSSimon Glass DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
142e59f458dSSimon Glass 
143e59f458dSSimon Glass /* Test that the bus can store data about each child */
144e59f458dSSimon Glass static int dm_test_bus_parent_data(struct dm_test_state *dms)
145e59f458dSSimon Glass {
146e59f458dSSimon Glass 	struct dm_test_parent_data *parent_data;
147e59f458dSSimon Glass 	struct udevice *bus, *dev;
148e59f458dSSimon Glass 	struct uclass *uc;
149e59f458dSSimon Glass 	int value;
150e59f458dSSimon Glass 
151e59f458dSSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
152e59f458dSSimon Glass 
153e59f458dSSimon Glass 	/* Check that parent data is allocated */
154e59f458dSSimon Glass 	ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
155e59f458dSSimon Glass 	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
156e59f458dSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
157e59f458dSSimon Glass 	parent_data = dev_get_parentdata(dev);
158e59f458dSSimon Glass 	ut_assert(NULL != parent_data);
159e59f458dSSimon Glass 
160e59f458dSSimon Glass 	/* Check that it starts at 0 and goes away when device is removed */
161e59f458dSSimon Glass 	parent_data->sum += 5;
162e59f458dSSimon Glass 	ut_asserteq(5, parent_data->sum);
163e59f458dSSimon Glass 	device_remove(dev);
164e59f458dSSimon Glass 	ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
165e59f458dSSimon Glass 
166e59f458dSSimon Glass 	/* Check that we can do this twice */
167e59f458dSSimon Glass 	ut_assertok(device_get_child_by_seq(bus, 0, &dev));
168e59f458dSSimon Glass 	parent_data = dev_get_parentdata(dev);
169e59f458dSSimon Glass 	ut_assert(NULL != parent_data);
170e59f458dSSimon Glass 	parent_data->sum += 5;
171e59f458dSSimon Glass 	ut_asserteq(5, parent_data->sum);
172e59f458dSSimon Glass 
173e59f458dSSimon Glass 	/* Add parent data to all children */
174e59f458dSSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
175e59f458dSSimon Glass 	value = 5;
176e59f458dSSimon Glass 	uclass_foreach_dev(dev, uc) {
177e59f458dSSimon Glass 		/* Ignore these if they are not on this bus */
178e59f458dSSimon Glass 		if (dev->parent != bus) {
179e59f458dSSimon Glass 			ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
180e59f458dSSimon Glass 			continue;
181e59f458dSSimon Glass 		}
182e59f458dSSimon Glass 		ut_assertok(device_probe(dev));
183e59f458dSSimon Glass 		parent_data = dev_get_parentdata(dev);
184e59f458dSSimon Glass 
185e59f458dSSimon Glass 		parent_data->sum = value;
186e59f458dSSimon Glass 		value += 5;
187e59f458dSSimon Glass 	}
188e59f458dSSimon Glass 
189e59f458dSSimon Glass 	/* Check it is still there */
190e59f458dSSimon Glass 	value = 5;
191e59f458dSSimon Glass 	uclass_foreach_dev(dev, uc) {
192e59f458dSSimon Glass 		/* Ignore these if they are not on this bus */
193e59f458dSSimon Glass 		if (dev->parent != bus)
194e59f458dSSimon Glass 			continue;
195e59f458dSSimon Glass 		parent_data = dev_get_parentdata(dev);
196e59f458dSSimon Glass 
197e59f458dSSimon Glass 		ut_asserteq(value, parent_data->sum);
198e59f458dSSimon Glass 		value += 5;
199e59f458dSSimon Glass 	}
200e59f458dSSimon Glass 
201e59f458dSSimon Glass 	return 0;
202e59f458dSSimon Glass }
203e59f458dSSimon Glass 
204e59f458dSSimon Glass DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
205*a327dee0SSimon Glass 
206*a327dee0SSimon Glass /* Test that the bus ops are called when a child is probed/removed */
207*a327dee0SSimon Glass static int dm_test_bus_parent_ops(struct dm_test_state *dms)
208*a327dee0SSimon Glass {
209*a327dee0SSimon Glass 	struct dm_test_parent_data *parent_data;
210*a327dee0SSimon Glass 	struct udevice *bus, *dev;
211*a327dee0SSimon Glass 	struct uclass *uc;
212*a327dee0SSimon Glass 
213*a327dee0SSimon Glass 	test_state = dms;
214*a327dee0SSimon Glass 	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
215*a327dee0SSimon Glass 	ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
216*a327dee0SSimon Glass 
217*a327dee0SSimon Glass 	uclass_foreach_dev(dev, uc) {
218*a327dee0SSimon Glass 		/* Ignore these if they are not on this bus */
219*a327dee0SSimon Glass 		if (dev->parent != bus)
220*a327dee0SSimon Glass 			continue;
221*a327dee0SSimon Glass 		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
222*a327dee0SSimon Glass 
223*a327dee0SSimon Glass 		ut_assertok(device_probe(dev));
224*a327dee0SSimon Glass 		parent_data = dev_get_parentdata(dev);
225*a327dee0SSimon Glass 		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
226*a327dee0SSimon Glass 	}
227*a327dee0SSimon Glass 
228*a327dee0SSimon Glass 	uclass_foreach_dev(dev, uc) {
229*a327dee0SSimon Glass 		/* Ignore these if they are not on this bus */
230*a327dee0SSimon Glass 		if (dev->parent != bus)
231*a327dee0SSimon Glass 			continue;
232*a327dee0SSimon Glass 		parent_data = dev_get_parentdata(dev);
233*a327dee0SSimon Glass 		ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
234*a327dee0SSimon Glass 		ut_assertok(device_remove(dev));
235*a327dee0SSimon Glass 		ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
236*a327dee0SSimon Glass 		ut_asserteq_ptr(dms->removed, dev);
237*a327dee0SSimon Glass 	}
238*a327dee0SSimon Glass 	test_state = NULL;
239*a327dee0SSimon Glass 
240*a327dee0SSimon Glass 	return 0;
241*a327dee0SSimon Glass }
242*a327dee0SSimon Glass DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
243