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/test.h>
11cdc133bdSSimon Glass #include <dm/uclass-internal.h>
121ca7e206SSimon Glass #include <dm/util.h>
13e721b882SJoe Hershberger #include <test/ut.h>
141ca7e206SSimon Glass
151ca7e206SSimon Glass DECLARE_GLOBAL_DATA_PTR;
161ca7e206SSimon Glass
17cdc133bdSSimon Glass struct dm_test_parent_platdata {
18cdc133bdSSimon Glass int count;
190118ce79SSimon Glass int bind_flag;
20081f2fcbSSimon Glass int uclass_bind_flag;
21cdc133bdSSimon Glass };
22cdc133bdSSimon Glass
23a327dee0SSimon Glass enum {
24a327dee0SSimon Glass FLAG_CHILD_PROBED = 10,
25a327dee0SSimon Glass FLAG_CHILD_REMOVED = -7,
26a327dee0SSimon Glass };
27a327dee0SSimon Glass
28a327dee0SSimon Glass static struct dm_test_state *test_state;
29a327dee0SSimon Glass
testbus_drv_probe(struct udevice * dev)301ca7e206SSimon Glass static int testbus_drv_probe(struct udevice *dev)
311ca7e206SSimon Glass {
322e3f1ff6SSimon Glass return dm_scan_fdt_dev(dev);
331ca7e206SSimon Glass }
341ca7e206SSimon Glass
testbus_child_post_bind(struct udevice * dev)350118ce79SSimon Glass static int testbus_child_post_bind(struct udevice *dev)
360118ce79SSimon Glass {
370118ce79SSimon Glass struct dm_test_parent_platdata *plat;
380118ce79SSimon Glass
390118ce79SSimon Glass plat = dev_get_parent_platdata(dev);
400118ce79SSimon Glass plat->bind_flag = 1;
41081f2fcbSSimon Glass plat->uclass_bind_flag = 2;
420118ce79SSimon Glass
430118ce79SSimon Glass return 0;
440118ce79SSimon Glass }
450118ce79SSimon Glass
testbus_child_pre_probe(struct udevice * dev)46a327dee0SSimon Glass static int testbus_child_pre_probe(struct udevice *dev)
47a327dee0SSimon Glass {
48bcbe3d15SSimon Glass struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
49a327dee0SSimon Glass
50a327dee0SSimon Glass parent_data->flag += FLAG_CHILD_PROBED;
51a327dee0SSimon Glass
52a327dee0SSimon Glass return 0;
53a327dee0SSimon Glass }
54a327dee0SSimon Glass
testbus_child_pre_probe_uclass(struct udevice * dev)5583c7e434SSimon Glass static int testbus_child_pre_probe_uclass(struct udevice *dev)
5683c7e434SSimon Glass {
5783c7e434SSimon Glass struct dm_test_priv *priv = dev_get_priv(dev);
5883c7e434SSimon Glass
5983c7e434SSimon Glass priv->uclass_flag++;
6083c7e434SSimon Glass
6183c7e434SSimon Glass return 0;
6283c7e434SSimon Glass }
6383c7e434SSimon Glass
testbus_child_post_remove(struct udevice * dev)64a327dee0SSimon Glass static int testbus_child_post_remove(struct udevice *dev)
65a327dee0SSimon Glass {
66bcbe3d15SSimon Glass struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
67a327dee0SSimon Glass struct dm_test_state *dms = test_state;
68a327dee0SSimon Glass
69a327dee0SSimon Glass parent_data->flag += FLAG_CHILD_REMOVED;
70a327dee0SSimon Glass if (dms)
71a327dee0SSimon Glass dms->removed = dev;
72a327dee0SSimon Glass
73a327dee0SSimon Glass return 0;
74a327dee0SSimon Glass }
75a327dee0SSimon Glass
761ca7e206SSimon Glass static const struct udevice_id testbus_ids[] = {
771ca7e206SSimon Glass {
781ca7e206SSimon Glass .compatible = "denx,u-boot-test-bus",
791ca7e206SSimon Glass .data = DM_TEST_TYPE_FIRST },
801ca7e206SSimon Glass { }
811ca7e206SSimon Glass };
821ca7e206SSimon Glass
831ca7e206SSimon Glass U_BOOT_DRIVER(testbus_drv) = {
841ca7e206SSimon Glass .name = "testbus_drv",
851ca7e206SSimon Glass .of_match = testbus_ids,
861ca7e206SSimon Glass .id = UCLASS_TEST_BUS,
871ca7e206SSimon Glass .probe = testbus_drv_probe,
880118ce79SSimon Glass .child_post_bind = testbus_child_post_bind,
891ca7e206SSimon Glass .priv_auto_alloc_size = sizeof(struct dm_test_priv),
901ca7e206SSimon Glass .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
91e59f458dSSimon Glass .per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
92cdc133bdSSimon Glass .per_child_platdata_auto_alloc_size =
93cdc133bdSSimon Glass sizeof(struct dm_test_parent_platdata),
94a327dee0SSimon Glass .child_pre_probe = testbus_child_pre_probe,
95a327dee0SSimon Glass .child_post_remove = testbus_child_post_remove,
961ca7e206SSimon Glass };
971ca7e206SSimon Glass
981ca7e206SSimon Glass UCLASS_DRIVER(testbus) = {
991ca7e206SSimon Glass .name = "testbus",
1001ca7e206SSimon Glass .id = UCLASS_TEST_BUS,
1019cc36a2bSSimon Glass .flags = DM_UC_FLAG_SEQ_ALIAS,
10283c7e434SSimon Glass .child_pre_probe = testbus_child_pre_probe_uclass,
1031ca7e206SSimon Glass };
1041ca7e206SSimon Glass
1051ca7e206SSimon Glass /* Test that we can probe for children */
dm_test_bus_children(struct unit_test_state * uts)106e721b882SJoe Hershberger static int dm_test_bus_children(struct unit_test_state *uts)
1071ca7e206SSimon Glass {
1089cc36a2bSSimon Glass int num_devices = 6;
1091ca7e206SSimon Glass struct udevice *bus;
1101ca7e206SSimon Glass struct uclass *uc;
1111ca7e206SSimon Glass
1121ca7e206SSimon Glass ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
1131ca7e206SSimon Glass ut_asserteq(num_devices, list_count_items(&uc->dev_head));
1141ca7e206SSimon Glass
1151ca7e206SSimon Glass /* Probe the bus, which should yield 3 more devices */
1161ca7e206SSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
1171ca7e206SSimon Glass num_devices += 3;
1181ca7e206SSimon Glass
1191ca7e206SSimon Glass ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
1201ca7e206SSimon Glass ut_asserteq(num_devices, list_count_items(&uc->dev_head));
1211ca7e206SSimon Glass
122e721b882SJoe Hershberger ut_assert(!dm_check_devices(uts, num_devices));
1231ca7e206SSimon Glass
1241ca7e206SSimon Glass return 0;
1251ca7e206SSimon Glass }
1261ca7e206SSimon Glass DM_TEST(dm_test_bus_children, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
127997c87bbSSimon Glass
128997c87bbSSimon Glass /* Test our functions for accessing children */
dm_test_bus_children_funcs(struct unit_test_state * uts)129e721b882SJoe Hershberger static int dm_test_bus_children_funcs(struct unit_test_state *uts)
130997c87bbSSimon Glass {
131997c87bbSSimon Glass const void *blob = gd->fdt_blob;
132997c87bbSSimon Glass struct udevice *bus, *dev;
133997c87bbSSimon Glass int node;
134997c87bbSSimon Glass
135997c87bbSSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
136997c87bbSSimon Glass
137997c87bbSSimon Glass /* device_get_child() */
138997c87bbSSimon Glass ut_assertok(device_get_child(bus, 0, &dev));
139997c87bbSSimon Glass ut_asserteq(-ENODEV, device_get_child(bus, 4, &dev));
140997c87bbSSimon Glass ut_assertok(device_get_child_by_seq(bus, 5, &dev));
141997c87bbSSimon Glass ut_assert(dev->flags & DM_FLAG_ACTIVATED);
142997c87bbSSimon Glass ut_asserteq_str("c-test@5", dev->name);
143997c87bbSSimon Glass
144997c87bbSSimon Glass /* Device with sequence number 0 should be accessible */
145997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_seq(bus, -1, true, &dev));
146997c87bbSSimon Glass ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
147997c87bbSSimon Glass ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
148997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 0, false, &dev));
149997c87bbSSimon Glass ut_assertok(device_get_child_by_seq(bus, 0, &dev));
150997c87bbSSimon Glass ut_assert(dev->flags & DM_FLAG_ACTIVATED);
151997c87bbSSimon Glass
152997c87bbSSimon Glass /* There is no device with sequence number 2 */
153997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, false, &dev));
154997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_seq(bus, 2, true, &dev));
155997c87bbSSimon Glass ut_asserteq(-ENODEV, device_get_child_by_seq(bus, 2, &dev));
156997c87bbSSimon Glass
157997c87bbSSimon Glass /* Looking for something that is not a child */
158997c87bbSSimon Glass node = fdt_path_offset(blob, "/junk");
159997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
160997c87bbSSimon Glass node = fdt_path_offset(blob, "/d-test");
161997c87bbSSimon Glass ut_asserteq(-ENODEV, device_find_child_by_of_offset(bus, node, &dev));
162997c87bbSSimon Glass
163298afb52SSimon Glass return 0;
164298afb52SSimon Glass }
165298afb52SSimon Glass DM_TEST(dm_test_bus_children_funcs, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
166298afb52SSimon Glass
dm_test_bus_children_of_offset(struct unit_test_state * uts)167298afb52SSimon Glass static int dm_test_bus_children_of_offset(struct unit_test_state *uts)
168298afb52SSimon Glass {
169298afb52SSimon Glass const void *blob = gd->fdt_blob;
170298afb52SSimon Glass struct udevice *bus, *dev;
171298afb52SSimon Glass int node;
172298afb52SSimon Glass
173298afb52SSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
174*4f414d39SSimon Glass ut_assertnonnull(bus);
175298afb52SSimon Glass
176997c87bbSSimon Glass /* Find a valid child */
177997c87bbSSimon Glass node = fdt_path_offset(blob, "/some-bus/c-test@1");
178298afb52SSimon Glass ut_assert(node > 0);
179997c87bbSSimon Glass ut_assertok(device_find_child_by_of_offset(bus, node, &dev));
180*4f414d39SSimon Glass ut_assertnonnull(dev);
181997c87bbSSimon Glass ut_assert(!(dev->flags & DM_FLAG_ACTIVATED));
182997c87bbSSimon Glass ut_assertok(device_get_child_by_of_offset(bus, node, &dev));
183*4f414d39SSimon Glass ut_assertnonnull(dev);
184997c87bbSSimon Glass ut_assert(dev->flags & DM_FLAG_ACTIVATED);
185997c87bbSSimon Glass
186997c87bbSSimon Glass return 0;
187997c87bbSSimon Glass }
188298afb52SSimon Glass DM_TEST(dm_test_bus_children_of_offset,
189298afb52SSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | DM_TESTF_FLAT_TREE);
190e59f458dSSimon Glass
191a8981d4fSSimon Glass /* Test that we can iterate through children */
dm_test_bus_children_iterators(struct unit_test_state * uts)192e721b882SJoe Hershberger static int dm_test_bus_children_iterators(struct unit_test_state *uts)
193a8981d4fSSimon Glass {
194a8981d4fSSimon Glass struct udevice *bus, *dev, *child;
195a8981d4fSSimon Glass
196a8981d4fSSimon Glass /* Walk through the children one by one */
197a8981d4fSSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
198a8981d4fSSimon Glass ut_assertok(device_find_first_child(bus, &dev));
199a8981d4fSSimon Glass ut_asserteq_str("c-test@5", dev->name);
200a8981d4fSSimon Glass ut_assertok(device_find_next_child(&dev));
201a8981d4fSSimon Glass ut_asserteq_str("c-test@0", dev->name);
202a8981d4fSSimon Glass ut_assertok(device_find_next_child(&dev));
203a8981d4fSSimon Glass ut_asserteq_str("c-test@1", dev->name);
204a8981d4fSSimon Glass ut_assertok(device_find_next_child(&dev));
205a8981d4fSSimon Glass ut_asserteq_ptr(dev, NULL);
206a8981d4fSSimon Glass
207a8981d4fSSimon Glass /* Move to the next child without using device_find_first_child() */
208a8981d4fSSimon Glass ut_assertok(device_find_child_by_seq(bus, 5, true, &dev));
209a8981d4fSSimon Glass ut_asserteq_str("c-test@5", dev->name);
210a8981d4fSSimon Glass ut_assertok(device_find_next_child(&dev));
211a8981d4fSSimon Glass ut_asserteq_str("c-test@0", dev->name);
212a8981d4fSSimon Glass
213a8981d4fSSimon Glass /* Try a device with no children */
214a8981d4fSSimon Glass ut_assertok(device_find_first_child(dev, &child));
215a8981d4fSSimon Glass ut_asserteq_ptr(child, NULL);
216a8981d4fSSimon Glass
217a8981d4fSSimon Glass return 0;
218a8981d4fSSimon Glass }
219a8981d4fSSimon Glass DM_TEST(dm_test_bus_children_iterators,
220a8981d4fSSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
221a8981d4fSSimon Glass
222e59f458dSSimon Glass /* Test that the bus can store data about each child */
test_bus_parent_data(struct unit_test_state * uts)223e721b882SJoe Hershberger static int test_bus_parent_data(struct unit_test_state *uts)
224e59f458dSSimon Glass {
225e59f458dSSimon Glass struct dm_test_parent_data *parent_data;
226e59f458dSSimon Glass struct udevice *bus, *dev;
227e59f458dSSimon Glass struct uclass *uc;
228e59f458dSSimon Glass int value;
229e59f458dSSimon Glass
230e59f458dSSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
231e59f458dSSimon Glass
232e59f458dSSimon Glass /* Check that parent data is allocated */
233e59f458dSSimon Glass ut_assertok(device_find_child_by_seq(bus, 0, true, &dev));
234bcbe3d15SSimon Glass ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
235e59f458dSSimon Glass ut_assertok(device_get_child_by_seq(bus, 0, &dev));
236bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
237e59f458dSSimon Glass ut_assert(NULL != parent_data);
238e59f458dSSimon Glass
239e59f458dSSimon Glass /* Check that it starts at 0 and goes away when device is removed */
240e59f458dSSimon Glass parent_data->sum += 5;
241e59f458dSSimon Glass ut_asserteq(5, parent_data->sum);
242706865afSStefan Roese device_remove(dev, DM_REMOVE_NORMAL);
243bcbe3d15SSimon Glass ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
244e59f458dSSimon Glass
245e59f458dSSimon Glass /* Check that we can do this twice */
246e59f458dSSimon Glass ut_assertok(device_get_child_by_seq(bus, 0, &dev));
247bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
248e59f458dSSimon Glass ut_assert(NULL != parent_data);
249e59f458dSSimon Glass parent_data->sum += 5;
250e59f458dSSimon Glass ut_asserteq(5, parent_data->sum);
251e59f458dSSimon Glass
252e59f458dSSimon Glass /* Add parent data to all children */
253e59f458dSSimon Glass ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
254e59f458dSSimon Glass value = 5;
255e59f458dSSimon Glass uclass_foreach_dev(dev, uc) {
256e59f458dSSimon Glass /* Ignore these if they are not on this bus */
257e59f458dSSimon Glass if (dev->parent != bus) {
258bcbe3d15SSimon Glass ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
259e59f458dSSimon Glass continue;
260e59f458dSSimon Glass }
261e59f458dSSimon Glass ut_assertok(device_probe(dev));
262bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
263e59f458dSSimon Glass
264e59f458dSSimon Glass parent_data->sum = value;
265e59f458dSSimon Glass value += 5;
266e59f458dSSimon Glass }
267e59f458dSSimon Glass
268e59f458dSSimon Glass /* Check it is still there */
269e59f458dSSimon Glass value = 5;
270e59f458dSSimon Glass uclass_foreach_dev(dev, uc) {
271e59f458dSSimon Glass /* Ignore these if they are not on this bus */
272e59f458dSSimon Glass if (dev->parent != bus)
273e59f458dSSimon Glass continue;
274bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
275e59f458dSSimon Glass
276e59f458dSSimon Glass ut_asserteq(value, parent_data->sum);
277e59f458dSSimon Glass value += 5;
278e59f458dSSimon Glass }
279e59f458dSSimon Glass
280e59f458dSSimon Glass return 0;
281e59f458dSSimon Glass }
282dac8db2cSSimon Glass /* Test that the bus can store data about each child */
dm_test_bus_parent_data(struct unit_test_state * uts)283e721b882SJoe Hershberger static int dm_test_bus_parent_data(struct unit_test_state *uts)
284dac8db2cSSimon Glass {
285e721b882SJoe Hershberger return test_bus_parent_data(uts);
286dac8db2cSSimon Glass }
287e59f458dSSimon Glass DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
288a327dee0SSimon Glass
289dac8db2cSSimon Glass /* As above but the size is controlled by the uclass */
dm_test_bus_parent_data_uclass(struct unit_test_state * uts)290e721b882SJoe Hershberger static int dm_test_bus_parent_data_uclass(struct unit_test_state *uts)
291dac8db2cSSimon Glass {
292e23eb614SSimon Glass struct driver *drv;
293dac8db2cSSimon Glass struct udevice *bus;
294dac8db2cSSimon Glass int size;
295dac8db2cSSimon Glass int ret;
296dac8db2cSSimon Glass
297dac8db2cSSimon Glass /* Set the driver size to 0 so that the uclass size is used */
298dac8db2cSSimon Glass ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
299e23eb614SSimon Glass drv = (struct driver *)bus->driver;
300e23eb614SSimon Glass size = drv->per_child_auto_alloc_size;
301dac8db2cSSimon Glass bus->uclass->uc_drv->per_child_auto_alloc_size = size;
302e23eb614SSimon Glass drv->per_child_auto_alloc_size = 0;
303e721b882SJoe Hershberger ret = test_bus_parent_data(uts);
304dac8db2cSSimon Glass if (ret)
305dac8db2cSSimon Glass return ret;
306dac8db2cSSimon Glass bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
307e23eb614SSimon Glass drv->per_child_auto_alloc_size = size;
308dac8db2cSSimon Glass
309dac8db2cSSimon Glass return 0;
310dac8db2cSSimon Glass }
311dac8db2cSSimon Glass DM_TEST(dm_test_bus_parent_data_uclass,
312dac8db2cSSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
313dac8db2cSSimon Glass
314a327dee0SSimon Glass /* Test that the bus ops are called when a child is probed/removed */
dm_test_bus_parent_ops(struct unit_test_state * uts)315e721b882SJoe Hershberger static int dm_test_bus_parent_ops(struct unit_test_state *uts)
316a327dee0SSimon Glass {
317a327dee0SSimon Glass struct dm_test_parent_data *parent_data;
318e721b882SJoe Hershberger struct dm_test_state *dms = uts->priv;
319a327dee0SSimon Glass struct udevice *bus, *dev;
320a327dee0SSimon Glass struct uclass *uc;
321a327dee0SSimon Glass
322a327dee0SSimon Glass test_state = dms;
323a327dee0SSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
324a327dee0SSimon Glass ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
325a327dee0SSimon Glass
326a327dee0SSimon Glass uclass_foreach_dev(dev, uc) {
327a327dee0SSimon Glass /* Ignore these if they are not on this bus */
328a327dee0SSimon Glass if (dev->parent != bus)
329a327dee0SSimon Glass continue;
330bcbe3d15SSimon Glass ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
331a327dee0SSimon Glass
332a327dee0SSimon Glass ut_assertok(device_probe(dev));
333bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
334a327dee0SSimon Glass ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
335a327dee0SSimon Glass }
336a327dee0SSimon Glass
337a327dee0SSimon Glass uclass_foreach_dev(dev, uc) {
338a327dee0SSimon Glass /* Ignore these if they are not on this bus */
339a327dee0SSimon Glass if (dev->parent != bus)
340a327dee0SSimon Glass continue;
341bcbe3d15SSimon Glass parent_data = dev_get_parent_priv(dev);
342a327dee0SSimon Glass ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
343706865afSStefan Roese ut_assertok(device_remove(dev, DM_REMOVE_NORMAL));
344bcbe3d15SSimon Glass ut_asserteq_ptr(NULL, dev_get_parent_priv(dev));
345a327dee0SSimon Glass ut_asserteq_ptr(dms->removed, dev);
346a327dee0SSimon Glass }
347a327dee0SSimon Glass test_state = NULL;
348a327dee0SSimon Glass
349a327dee0SSimon Glass return 0;
350a327dee0SSimon Glass }
351a327dee0SSimon Glass DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
352cdc133bdSSimon Glass
test_bus_parent_platdata(struct unit_test_state * uts)353e721b882SJoe Hershberger static int test_bus_parent_platdata(struct unit_test_state *uts)
354cdc133bdSSimon Glass {
355cdc133bdSSimon Glass struct dm_test_parent_platdata *plat;
356cdc133bdSSimon Glass struct udevice *bus, *dev;
357cdc133bdSSimon Glass int child_count;
358cdc133bdSSimon Glass
359cdc133bdSSimon Glass /* Check that the bus has no children */
360cdc133bdSSimon Glass ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
361cdc133bdSSimon Glass device_find_first_child(bus, &dev);
362cdc133bdSSimon Glass ut_asserteq_ptr(NULL, dev);
363cdc133bdSSimon Glass
364cdc133bdSSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
365cdc133bdSSimon Glass
366cdc133bdSSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
367cdc133bdSSimon Glass dev;
368cdc133bdSSimon Glass device_find_next_child(&dev)) {
369cdc133bdSSimon Glass /* Check that platform data is allocated */
370cdc133bdSSimon Glass plat = dev_get_parent_platdata(dev);
371cdc133bdSSimon Glass ut_assert(plat != NULL);
372cdc133bdSSimon Glass
373cdc133bdSSimon Glass /*
374cdc133bdSSimon Glass * Check that it is not affected by the device being
375cdc133bdSSimon Glass * probed/removed
376cdc133bdSSimon Glass */
377cdc133bdSSimon Glass plat->count++;
378cdc133bdSSimon Glass ut_asserteq(1, plat->count);
379cdc133bdSSimon Glass device_probe(dev);
380706865afSStefan Roese device_remove(dev, DM_REMOVE_NORMAL);
381cdc133bdSSimon Glass
382cdc133bdSSimon Glass ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
383cdc133bdSSimon Glass ut_asserteq(1, plat->count);
384cdc133bdSSimon Glass ut_assertok(device_probe(dev));
385cdc133bdSSimon Glass child_count++;
386cdc133bdSSimon Glass }
387cdc133bdSSimon Glass ut_asserteq(3, child_count);
388cdc133bdSSimon Glass
389cdc133bdSSimon Glass /* Removing the bus should also have no effect (it is still bound) */
390706865afSStefan Roese device_remove(bus, DM_REMOVE_NORMAL);
391cdc133bdSSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
392cdc133bdSSimon Glass dev;
393cdc133bdSSimon Glass device_find_next_child(&dev)) {
394cdc133bdSSimon Glass /* Check that platform data is allocated */
395cdc133bdSSimon Glass plat = dev_get_parent_platdata(dev);
396cdc133bdSSimon Glass ut_assert(plat != NULL);
397cdc133bdSSimon Glass ut_asserteq(1, plat->count);
398cdc133bdSSimon Glass child_count++;
399cdc133bdSSimon Glass }
400cdc133bdSSimon Glass ut_asserteq(3, child_count);
401cdc133bdSSimon Glass
402cdc133bdSSimon Glass /* Unbind all the children */
403cdc133bdSSimon Glass do {
404cdc133bdSSimon Glass device_find_first_child(bus, &dev);
405cdc133bdSSimon Glass if (dev)
406cdc133bdSSimon Glass device_unbind(dev);
407cdc133bdSSimon Glass } while (dev);
408cdc133bdSSimon Glass
409cdc133bdSSimon Glass /* Now the child platdata should be removed and re-added */
410cdc133bdSSimon Glass device_probe(bus);
411cdc133bdSSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
412cdc133bdSSimon Glass dev;
413cdc133bdSSimon Glass device_find_next_child(&dev)) {
414cdc133bdSSimon Glass /* Check that platform data is allocated */
415cdc133bdSSimon Glass plat = dev_get_parent_platdata(dev);
416cdc133bdSSimon Glass ut_assert(plat != NULL);
417cdc133bdSSimon Glass ut_asserteq(0, plat->count);
418cdc133bdSSimon Glass child_count++;
419cdc133bdSSimon Glass }
420cdc133bdSSimon Glass ut_asserteq(3, child_count);
421cdc133bdSSimon Glass
422cdc133bdSSimon Glass return 0;
423cdc133bdSSimon Glass }
424ba8da9dcSSimon Glass
425ba8da9dcSSimon Glass /* Test that the bus can store platform data about each child */
dm_test_bus_parent_platdata(struct unit_test_state * uts)426e721b882SJoe Hershberger static int dm_test_bus_parent_platdata(struct unit_test_state *uts)
427ba8da9dcSSimon Glass {
428e721b882SJoe Hershberger return test_bus_parent_platdata(uts);
429ba8da9dcSSimon Glass }
430cdc133bdSSimon Glass DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
431ba8da9dcSSimon Glass
432ba8da9dcSSimon Glass /* As above but the size is controlled by the uclass */
dm_test_bus_parent_platdata_uclass(struct unit_test_state * uts)433e721b882SJoe Hershberger static int dm_test_bus_parent_platdata_uclass(struct unit_test_state *uts)
434ba8da9dcSSimon Glass {
435ba8da9dcSSimon Glass struct udevice *bus;
436e23eb614SSimon Glass struct driver *drv;
437ba8da9dcSSimon Glass int size;
438ba8da9dcSSimon Glass int ret;
439ba8da9dcSSimon Glass
440ba8da9dcSSimon Glass /* Set the driver size to 0 so that the uclass size is used */
441ba8da9dcSSimon Glass ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
442e23eb614SSimon Glass drv = (struct driver *)bus->driver;
443e23eb614SSimon Glass size = drv->per_child_platdata_auto_alloc_size;
444ba8da9dcSSimon Glass bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
445e23eb614SSimon Glass drv->per_child_platdata_auto_alloc_size = 0;
446e721b882SJoe Hershberger ret = test_bus_parent_platdata(uts);
447ba8da9dcSSimon Glass if (ret)
448ba8da9dcSSimon Glass return ret;
449ba8da9dcSSimon Glass bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
450e23eb614SSimon Glass drv->per_child_platdata_auto_alloc_size = size;
451ba8da9dcSSimon Glass
452ba8da9dcSSimon Glass return 0;
453ba8da9dcSSimon Glass }
454ba8da9dcSSimon Glass DM_TEST(dm_test_bus_parent_platdata_uclass,
455ba8da9dcSSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
4560118ce79SSimon Glass
4570118ce79SSimon Glass /* Test that the child post_bind method is called */
dm_test_bus_child_post_bind(struct unit_test_state * uts)458e721b882SJoe Hershberger static int dm_test_bus_child_post_bind(struct unit_test_state *uts)
4590118ce79SSimon Glass {
4600118ce79SSimon Glass struct dm_test_parent_platdata *plat;
4610118ce79SSimon Glass struct udevice *bus, *dev;
4620118ce79SSimon Glass int child_count;
4630118ce79SSimon Glass
4640118ce79SSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
4650118ce79SSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
4660118ce79SSimon Glass dev;
4670118ce79SSimon Glass device_find_next_child(&dev)) {
4680118ce79SSimon Glass /* Check that platform data is allocated */
4690118ce79SSimon Glass plat = dev_get_parent_platdata(dev);
4700118ce79SSimon Glass ut_assert(plat != NULL);
4710118ce79SSimon Glass ut_asserteq(1, plat->bind_flag);
4720118ce79SSimon Glass child_count++;
4730118ce79SSimon Glass }
4740118ce79SSimon Glass ut_asserteq(3, child_count);
4750118ce79SSimon Glass
4760118ce79SSimon Glass return 0;
4770118ce79SSimon Glass }
4780118ce79SSimon Glass DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
479081f2fcbSSimon Glass
480081f2fcbSSimon Glass /* Test that the child post_bind method is called */
dm_test_bus_child_post_bind_uclass(struct unit_test_state * uts)481e721b882SJoe Hershberger static int dm_test_bus_child_post_bind_uclass(struct unit_test_state *uts)
482081f2fcbSSimon Glass {
483081f2fcbSSimon Glass struct dm_test_parent_platdata *plat;
484081f2fcbSSimon Glass struct udevice *bus, *dev;
485081f2fcbSSimon Glass int child_count;
486081f2fcbSSimon Glass
487081f2fcbSSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
488081f2fcbSSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
489081f2fcbSSimon Glass dev;
490081f2fcbSSimon Glass device_find_next_child(&dev)) {
491081f2fcbSSimon Glass /* Check that platform data is allocated */
492081f2fcbSSimon Glass plat = dev_get_parent_platdata(dev);
493081f2fcbSSimon Glass ut_assert(plat != NULL);
494081f2fcbSSimon Glass ut_asserteq(2, plat->uclass_bind_flag);
495081f2fcbSSimon Glass child_count++;
496081f2fcbSSimon Glass }
497081f2fcbSSimon Glass ut_asserteq(3, child_count);
498081f2fcbSSimon Glass
499081f2fcbSSimon Glass return 0;
500081f2fcbSSimon Glass }
501081f2fcbSSimon Glass DM_TEST(dm_test_bus_child_post_bind_uclass,
502081f2fcbSSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
50383c7e434SSimon Glass
50483c7e434SSimon Glass /*
50583c7e434SSimon Glass * Test that the bus' uclass' child_pre_probe() is called before the
50683c7e434SSimon Glass * device's probe() method
50783c7e434SSimon Glass */
dm_test_bus_child_pre_probe_uclass(struct unit_test_state * uts)508e721b882SJoe Hershberger static int dm_test_bus_child_pre_probe_uclass(struct unit_test_state *uts)
50983c7e434SSimon Glass {
51083c7e434SSimon Glass struct udevice *bus, *dev;
51183c7e434SSimon Glass int child_count;
51283c7e434SSimon Glass
51383c7e434SSimon Glass /*
51483c7e434SSimon Glass * See testfdt_drv_probe() which effectively checks that the uclass
51583c7e434SSimon Glass * flag is set before that method is called
51683c7e434SSimon Glass */
51783c7e434SSimon Glass ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
51883c7e434SSimon Glass for (device_find_first_child(bus, &dev), child_count = 0;
51983c7e434SSimon Glass dev;
52083c7e434SSimon Glass device_find_next_child(&dev)) {
52183c7e434SSimon Glass struct dm_test_priv *priv = dev_get_priv(dev);
52283c7e434SSimon Glass
52383c7e434SSimon Glass /* Check that things happened in the right order */
52483c7e434SSimon Glass ut_asserteq_ptr(NULL, priv);
52583c7e434SSimon Glass ut_assertok(device_probe(dev));
52683c7e434SSimon Glass
52783c7e434SSimon Glass priv = dev_get_priv(dev);
52883c7e434SSimon Glass ut_assert(priv != NULL);
52983c7e434SSimon Glass ut_asserteq(1, priv->uclass_flag);
53083c7e434SSimon Glass ut_asserteq(1, priv->uclass_total);
53183c7e434SSimon Glass child_count++;
53283c7e434SSimon Glass }
53383c7e434SSimon Glass ut_asserteq(3, child_count);
53483c7e434SSimon Glass
53583c7e434SSimon Glass return 0;
53683c7e434SSimon Glass }
53783c7e434SSimon Glass DM_TEST(dm_test_bus_child_pre_probe_uclass,
53883c7e434SSimon Glass DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
539