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