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