xref: /OK3568_Linux_fs/u-boot/test/dm/test-fdt.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2013 Google, Inc
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <common.h>
8*4882a593Smuzhiyun #include <dm.h>
9*4882a593Smuzhiyun #include <errno.h>
10*4882a593Smuzhiyun #include <fdtdec.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <dm/test.h>
14*4882a593Smuzhiyun #include <dm/root.h>
15*4882a593Smuzhiyun #include <dm/device-internal.h>
16*4882a593Smuzhiyun #include <dm/uclass-internal.h>
17*4882a593Smuzhiyun #include <dm/util.h>
18*4882a593Smuzhiyun #include <test/ut.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
21*4882a593Smuzhiyun 
testfdt_drv_ping(struct udevice * dev,int pingval,int * pingret)22*4882a593Smuzhiyun static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun 	const struct dm_test_pdata *pdata = dev->platdata;
25*4882a593Smuzhiyun 	struct dm_test_priv *priv = dev_get_priv(dev);
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	*pingret = pingval + pdata->ping_add;
28*4882a593Smuzhiyun 	priv->ping_total += *pingret;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	return 0;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun static const struct test_ops test_ops = {
34*4882a593Smuzhiyun 	.ping = testfdt_drv_ping,
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun 
testfdt_ofdata_to_platdata(struct udevice * dev)37*4882a593Smuzhiyun static int testfdt_ofdata_to_platdata(struct udevice *dev)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct dm_test_pdata *pdata = dev_get_platdata(dev);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	pdata->ping_add = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
42*4882a593Smuzhiyun 					"ping-add", -1);
43*4882a593Smuzhiyun 	pdata->base = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev),
44*4882a593Smuzhiyun 				      "ping-expect");
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
testfdt_drv_probe(struct udevice * dev)49*4882a593Smuzhiyun static int testfdt_drv_probe(struct udevice *dev)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct dm_test_priv *priv = dev_get_priv(dev);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	priv->ping_total += DM_TEST_START_TOTAL;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/*
56*4882a593Smuzhiyun 	 * If this device is on a bus, the uclass_flag will be set before
57*4882a593Smuzhiyun 	 * calling this function. This is used by
58*4882a593Smuzhiyun 	 * dm_test_bus_child_pre_probe_uclass().
59*4882a593Smuzhiyun 	 */
60*4882a593Smuzhiyun 	priv->uclass_total += priv->uclass_flag;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	return 0;
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun static const struct udevice_id testfdt_ids[] = {
66*4882a593Smuzhiyun 	{
67*4882a593Smuzhiyun 		.compatible = "denx,u-boot-fdt-test",
68*4882a593Smuzhiyun 		.data = DM_TEST_TYPE_FIRST },
69*4882a593Smuzhiyun 	{
70*4882a593Smuzhiyun 		.compatible = "google,another-fdt-test",
71*4882a593Smuzhiyun 		.data = DM_TEST_TYPE_SECOND },
72*4882a593Smuzhiyun 	{ }
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun U_BOOT_DRIVER(testfdt_drv) = {
76*4882a593Smuzhiyun 	.name	= "testfdt_drv",
77*4882a593Smuzhiyun 	.of_match	= testfdt_ids,
78*4882a593Smuzhiyun 	.id	= UCLASS_TEST_FDT,
79*4882a593Smuzhiyun 	.ofdata_to_platdata = testfdt_ofdata_to_platdata,
80*4882a593Smuzhiyun 	.probe	= testfdt_drv_probe,
81*4882a593Smuzhiyun 	.ops	= &test_ops,
82*4882a593Smuzhiyun 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
83*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun /* From here is the testfdt uclass code */
testfdt_ping(struct udevice * dev,int pingval,int * pingret)87*4882a593Smuzhiyun int testfdt_ping(struct udevice *dev, int pingval, int *pingret)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	const struct test_ops *ops = device_get_ops(dev);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	if (!ops->ping)
92*4882a593Smuzhiyun 		return -ENOSYS;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	return ops->ping(dev, pingval, pingret);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun UCLASS_DRIVER(testfdt) = {
98*4882a593Smuzhiyun 	.name		= "testfdt",
99*4882a593Smuzhiyun 	.id		= UCLASS_TEST_FDT,
100*4882a593Smuzhiyun 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun struct dm_testprobe_pdata {
104*4882a593Smuzhiyun 	int probe_err;
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
testprobe_drv_probe(struct udevice * dev)107*4882a593Smuzhiyun static int testprobe_drv_probe(struct udevice *dev)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	struct dm_testprobe_pdata *pdata = dev_get_platdata(dev);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	return pdata->probe_err;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static const struct udevice_id testprobe_ids[] = {
115*4882a593Smuzhiyun 	{ .compatible = "denx,u-boot-probe-test" },
116*4882a593Smuzhiyun 	{ }
117*4882a593Smuzhiyun };
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun U_BOOT_DRIVER(testprobe_drv) = {
120*4882a593Smuzhiyun 	.name	= "testprobe_drv",
121*4882a593Smuzhiyun 	.of_match	= testprobe_ids,
122*4882a593Smuzhiyun 	.id	= UCLASS_TEST_PROBE,
123*4882a593Smuzhiyun 	.probe	= testprobe_drv_probe,
124*4882a593Smuzhiyun 	.platdata_auto_alloc_size	= sizeof(struct dm_testprobe_pdata),
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun UCLASS_DRIVER(testprobe) = {
128*4882a593Smuzhiyun 	.name		= "testprobe",
129*4882a593Smuzhiyun 	.id		= UCLASS_TEST_PROBE,
130*4882a593Smuzhiyun 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun 
dm_check_devices(struct unit_test_state * uts,int num_devices)133*4882a593Smuzhiyun int dm_check_devices(struct unit_test_state *uts, int num_devices)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	struct udevice *dev;
136*4882a593Smuzhiyun 	int ret;
137*4882a593Smuzhiyun 	int i;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/*
140*4882a593Smuzhiyun 	 * Now check that the ping adds are what we expect. This is using the
141*4882a593Smuzhiyun 	 * ping-add property in each node.
142*4882a593Smuzhiyun 	 */
143*4882a593Smuzhiyun 	for (i = 0; i < num_devices; i++) {
144*4882a593Smuzhiyun 		uint32_t base;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		ret = uclass_get_device(UCLASS_TEST_FDT, i, &dev);
147*4882a593Smuzhiyun 		ut_assert(!ret);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		/*
150*4882a593Smuzhiyun 		 * Get the 'ping-expect' property, which tells us what the
151*4882a593Smuzhiyun 		 * ping add should be. We don't use the platdata because we
152*4882a593Smuzhiyun 		 * want to test the code that sets that up
153*4882a593Smuzhiyun 		 * (testfdt_drv_probe()).
154*4882a593Smuzhiyun 		 */
155*4882a593Smuzhiyun 		base = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev),
156*4882a593Smuzhiyun 				       "ping-expect");
157*4882a593Smuzhiyun 		debug("dev=%d, base=%d: %s\n", i, base,
158*4882a593Smuzhiyun 		      fdt_get_name(gd->fdt_blob, dev_of_offset(dev), NULL));
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 		ut_assert(!dm_check_operations(uts, dev, base,
161*4882a593Smuzhiyun 					       dev_get_priv(dev)));
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /* Test that FDT-based binding works correctly */
dm_test_fdt(struct unit_test_state * uts)168*4882a593Smuzhiyun static int dm_test_fdt(struct unit_test_state *uts)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	const int num_devices = 6;
171*4882a593Smuzhiyun 	struct udevice *dev;
172*4882a593Smuzhiyun 	struct uclass *uc;
173*4882a593Smuzhiyun 	int ret;
174*4882a593Smuzhiyun 	int i;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	ret = dm_scan_fdt(gd->fdt_blob, false);
177*4882a593Smuzhiyun 	ut_assert(!ret);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_TEST_FDT, &uc);
180*4882a593Smuzhiyun 	ut_assert(!ret);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	/* These are num_devices compatible root-level device tree nodes */
183*4882a593Smuzhiyun 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	/* Each should have platform data but no private data */
186*4882a593Smuzhiyun 	for (i = 0; i < num_devices; i++) {
187*4882a593Smuzhiyun 		ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
188*4882a593Smuzhiyun 		ut_assert(!ret);
189*4882a593Smuzhiyun 		ut_assert(!dev_get_priv(dev));
190*4882a593Smuzhiyun 		ut_assert(dev->platdata);
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	ut_assertok(dm_check_devices(uts, num_devices));
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun DM_TEST(dm_test_fdt, 0);
198*4882a593Smuzhiyun 
dm_test_fdt_pre_reloc(struct unit_test_state * uts)199*4882a593Smuzhiyun static int dm_test_fdt_pre_reloc(struct unit_test_state *uts)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct uclass *uc;
202*4882a593Smuzhiyun 	int ret;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	ret = dm_scan_fdt(gd->fdt_blob, true);
205*4882a593Smuzhiyun 	ut_assert(!ret);
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	ret = uclass_get(UCLASS_TEST_FDT, &uc);
208*4882a593Smuzhiyun 	ut_assert(!ret);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	/* These is only one pre-reloc device */
211*4882a593Smuzhiyun 	ut_asserteq(1, list_count_items(&uc->dev_head));
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun DM_TEST(dm_test_fdt_pre_reloc, 0);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun /* Test that sequence numbers are allocated properly */
dm_test_fdt_uclass_seq(struct unit_test_state * uts)218*4882a593Smuzhiyun static int dm_test_fdt_uclass_seq(struct unit_test_state *uts)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	struct udevice *dev;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* A few basic santiy tests */
223*4882a593Smuzhiyun 	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev));
224*4882a593Smuzhiyun 	ut_asserteq_str("b-test", dev->name);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 8, true, &dev));
227*4882a593Smuzhiyun 	ut_asserteq_str("a-test", dev->name);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
230*4882a593Smuzhiyun 						       true, &dev));
231*4882a593Smuzhiyun 	ut_asserteq_ptr(NULL, dev);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* Test aliases */
234*4882a593Smuzhiyun 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 6, &dev));
235*4882a593Smuzhiyun 	ut_asserteq_str("e-test", dev->name);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 7,
238*4882a593Smuzhiyun 						       true, &dev));
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	/*
241*4882a593Smuzhiyun 	 * Note that c-test nodes are not probed since it is not a top-level
242*4882a593Smuzhiyun 	 * node
243*4882a593Smuzhiyun 	 */
244*4882a593Smuzhiyun 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev));
245*4882a593Smuzhiyun 	ut_asserteq_str("b-test", dev->name);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/*
248*4882a593Smuzhiyun 	 * d-test wants sequence number 3 also, but it can't have it because
249*4882a593Smuzhiyun 	 * b-test gets it first.
250*4882a593Smuzhiyun 	 */
251*4882a593Smuzhiyun 	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 2, &dev));
252*4882a593Smuzhiyun 	ut_asserteq_str("d-test", dev->name);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* d-test actually gets 0 */
255*4882a593Smuzhiyun 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 0, &dev));
256*4882a593Smuzhiyun 	ut_asserteq_str("d-test", dev->name);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	/* initially no one wants seq 1 */
259*4882a593Smuzhiyun 	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1,
260*4882a593Smuzhiyun 						      &dev));
261*4882a593Smuzhiyun 	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
262*4882a593Smuzhiyun 	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 4, &dev));
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	/* But now that it is probed, we can find it */
265*4882a593Smuzhiyun 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev));
266*4882a593Smuzhiyun 	ut_asserteq_str("f-test", dev->name);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	return 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun DM_TEST(dm_test_fdt_uclass_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /* Test that we can find a device by device tree offset */
dm_test_fdt_offset(struct unit_test_state * uts)273*4882a593Smuzhiyun static int dm_test_fdt_offset(struct unit_test_state *uts)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun 	const void *blob = gd->fdt_blob;
276*4882a593Smuzhiyun 	struct udevice *dev;
277*4882a593Smuzhiyun 	int node;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	node = fdt_path_offset(blob, "/e-test");
280*4882a593Smuzhiyun 	ut_assert(node > 0);
281*4882a593Smuzhiyun 	ut_assertok(uclass_get_device_by_of_offset(UCLASS_TEST_FDT, node,
282*4882a593Smuzhiyun 						   &dev));
283*4882a593Smuzhiyun 	ut_asserteq_str("e-test", dev->name);
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	/* This node should not be bound */
286*4882a593Smuzhiyun 	node = fdt_path_offset(blob, "/junk");
287*4882a593Smuzhiyun 	ut_assert(node > 0);
288*4882a593Smuzhiyun 	ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
289*4882a593Smuzhiyun 							    node, &dev));
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* This is not a top level node so should not be probed */
292*4882a593Smuzhiyun 	node = fdt_path_offset(blob, "/some-bus/c-test@5");
293*4882a593Smuzhiyun 	ut_assert(node > 0);
294*4882a593Smuzhiyun 	ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT,
295*4882a593Smuzhiyun 							    node, &dev));
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return 0;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun DM_TEST(dm_test_fdt_offset,
300*4882a593Smuzhiyun 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun /**
303*4882a593Smuzhiyun  * Test various error conditions with uclass_first_device() and
304*4882a593Smuzhiyun  * uclass_next_device()
305*4882a593Smuzhiyun  */
dm_test_first_next_device(struct unit_test_state * uts)306*4882a593Smuzhiyun static int dm_test_first_next_device(struct unit_test_state *uts)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	struct dm_testprobe_pdata *pdata;
309*4882a593Smuzhiyun 	struct udevice *dev, *parent = NULL;
310*4882a593Smuzhiyun 	int count;
311*4882a593Smuzhiyun 	int ret;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/* There should be 4 devices */
314*4882a593Smuzhiyun 	for (ret = uclass_first_device(UCLASS_TEST_PROBE, &dev), count = 0;
315*4882a593Smuzhiyun 	     dev;
316*4882a593Smuzhiyun 	     ret = uclass_next_device(&dev)) {
317*4882a593Smuzhiyun 		count++;
318*4882a593Smuzhiyun 		parent = dev_get_parent(dev);
319*4882a593Smuzhiyun 		}
320*4882a593Smuzhiyun 	ut_assertok(ret);
321*4882a593Smuzhiyun 	ut_asserteq(4, count);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	/* Remove them and try again, with an error on the second one */
324*4882a593Smuzhiyun 	ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 1, &dev));
325*4882a593Smuzhiyun 	pdata = dev_get_platdata(dev);
326*4882a593Smuzhiyun 	pdata->probe_err = -ENOMEM;
327*4882a593Smuzhiyun 	device_remove(parent, DM_REMOVE_NORMAL);
328*4882a593Smuzhiyun 	ut_assertok(uclass_first_device(UCLASS_TEST_PROBE, &dev));
329*4882a593Smuzhiyun 	ut_asserteq(-ENOMEM, uclass_next_device(&dev));
330*4882a593Smuzhiyun 	ut_asserteq_ptr(dev, NULL);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Now an error on the first one */
333*4882a593Smuzhiyun 	ut_assertok(uclass_get_device(UCLASS_TEST_PROBE, 0, &dev));
334*4882a593Smuzhiyun 	pdata = dev_get_platdata(dev);
335*4882a593Smuzhiyun 	pdata->probe_err = -ENOENT;
336*4882a593Smuzhiyun 	device_remove(parent, DM_REMOVE_NORMAL);
337*4882a593Smuzhiyun 	ut_asserteq(-ENOENT, uclass_first_device(UCLASS_TEST_PROBE, &dev));
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun /**
344*4882a593Smuzhiyun  * check_devices() - Check return values and pointers
345*4882a593Smuzhiyun  *
346*4882a593Smuzhiyun  * This runs through a full sequence of uclass_first_device_check()...
347*4882a593Smuzhiyun  * uclass_next_device_check() checking that the return values and devices
348*4882a593Smuzhiyun  * are correct.
349*4882a593Smuzhiyun  *
350*4882a593Smuzhiyun  * @uts: Test state
351*4882a593Smuzhiyun  * @devlist: List of expected devices
352*4882a593Smuzhiyun  * @mask: Indicates which devices should return an error. Device n should
353*4882a593Smuzhiyun  *	  return error (-NOENT - n) if bit n is set, or no error (i.e. 0) if
354*4882a593Smuzhiyun  *	  bit n is clear.
355*4882a593Smuzhiyun  */
check_devices(struct unit_test_state * uts,struct udevice * devlist[],int mask)356*4882a593Smuzhiyun static int check_devices(struct unit_test_state *uts,
357*4882a593Smuzhiyun 			 struct udevice *devlist[], int mask)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	int expected_ret;
360*4882a593Smuzhiyun 	struct udevice *dev;
361*4882a593Smuzhiyun 	int i;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	expected_ret = (mask & 1) ? -ENOENT : 0;
364*4882a593Smuzhiyun 	mask >>= 1;
365*4882a593Smuzhiyun 	ut_asserteq(expected_ret,
366*4882a593Smuzhiyun 		    uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
367*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
368*4882a593Smuzhiyun 		ut_asserteq_ptr(devlist[i], dev);
369*4882a593Smuzhiyun 		expected_ret = (mask & 1) ? -ENOENT - (i + 1) : 0;
370*4882a593Smuzhiyun 		mask >>= 1;
371*4882a593Smuzhiyun 		ut_asserteq(expected_ret, uclass_next_device_check(&dev));
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 	ut_asserteq_ptr(NULL, dev);
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun /* Test uclass_first_device_check() and uclass_next_device_check() */
dm_test_first_next_ok_device(struct unit_test_state * uts)379*4882a593Smuzhiyun static int dm_test_first_next_ok_device(struct unit_test_state *uts)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct dm_testprobe_pdata *pdata;
382*4882a593Smuzhiyun 	struct udevice *dev, *parent = NULL, *devlist[4];
383*4882a593Smuzhiyun 	int count;
384*4882a593Smuzhiyun 	int ret;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	/* There should be 4 devices */
387*4882a593Smuzhiyun 	count = 0;
388*4882a593Smuzhiyun 	for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev);
389*4882a593Smuzhiyun 	     dev;
390*4882a593Smuzhiyun 	     ret = uclass_next_device_check(&dev)) {
391*4882a593Smuzhiyun 		ut_assertok(ret);
392*4882a593Smuzhiyun 		devlist[count++] = dev;
393*4882a593Smuzhiyun 		parent = dev_get_parent(dev);
394*4882a593Smuzhiyun 		}
395*4882a593Smuzhiyun 	ut_asserteq(4, count);
396*4882a593Smuzhiyun 	ut_assertok(uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
397*4882a593Smuzhiyun 	ut_assertok(check_devices(uts, devlist, 0));
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* Remove them and try again, with an error on the second one */
400*4882a593Smuzhiyun 	pdata = dev_get_platdata(devlist[1]);
401*4882a593Smuzhiyun 	pdata->probe_err = -ENOENT - 1;
402*4882a593Smuzhiyun 	device_remove(parent, DM_REMOVE_NORMAL);
403*4882a593Smuzhiyun 	ut_assertok(check_devices(uts, devlist, 1 << 1));
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	/* Now an error on the first one */
406*4882a593Smuzhiyun 	pdata = dev_get_platdata(devlist[0]);
407*4882a593Smuzhiyun 	pdata->probe_err = -ENOENT - 0;
408*4882a593Smuzhiyun 	device_remove(parent, DM_REMOVE_NORMAL);
409*4882a593Smuzhiyun 	ut_assertok(check_devices(uts, devlist, 3 << 0));
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	/* Now errors on all */
412*4882a593Smuzhiyun 	pdata = dev_get_platdata(devlist[2]);
413*4882a593Smuzhiyun 	pdata->probe_err = -ENOENT - 2;
414*4882a593Smuzhiyun 	pdata = dev_get_platdata(devlist[3]);
415*4882a593Smuzhiyun 	pdata->probe_err = -ENOENT - 3;
416*4882a593Smuzhiyun 	device_remove(parent, DM_REMOVE_NORMAL);
417*4882a593Smuzhiyun 	ut_assertok(check_devices(uts, devlist, 0xf << 0));
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
422