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