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/ut.h> 16 #include <dm/uclass-internal.h> 17 #include <dm/util.h> 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret) 22 { 23 const struct dm_test_pdata *pdata = dev->platdata; 24 struct dm_test_priv *priv = dev_get_priv(dev); 25 26 *pingret = pingval + pdata->ping_add; 27 priv->ping_total += *pingret; 28 29 return 0; 30 } 31 32 static const struct test_ops test_ops = { 33 .ping = testfdt_drv_ping, 34 }; 35 36 static int testfdt_ofdata_to_platdata(struct udevice *dev) 37 { 38 struct dm_test_pdata *pdata = dev_get_platdata(dev); 39 40 pdata->ping_add = fdtdec_get_int(gd->fdt_blob, dev->of_offset, 41 "ping-add", -1); 42 pdata->base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, 43 "ping-expect"); 44 45 return 0; 46 } 47 48 static int testfdt_drv_probe(struct udevice *dev) 49 { 50 struct dm_test_priv *priv = dev_get_priv(dev); 51 52 priv->ping_total += DM_TEST_START_TOTAL; 53 54 return 0; 55 } 56 57 static const struct udevice_id testfdt_ids[] = { 58 { 59 .compatible = "denx,u-boot-fdt-test", 60 .data = DM_TEST_TYPE_FIRST }, 61 { 62 .compatible = "google,another-fdt-test", 63 .data = DM_TEST_TYPE_SECOND }, 64 { } 65 }; 66 67 U_BOOT_DRIVER(testfdt_drv) = { 68 .name = "testfdt_drv", 69 .of_match = testfdt_ids, 70 .id = UCLASS_TEST_FDT, 71 .ofdata_to_platdata = testfdt_ofdata_to_platdata, 72 .probe = testfdt_drv_probe, 73 .ops = &test_ops, 74 .priv_auto_alloc_size = sizeof(struct dm_test_priv), 75 .platdata_auto_alloc_size = sizeof(struct dm_test_pdata), 76 }; 77 78 /* From here is the testfdt uclass code */ 79 int testfdt_ping(struct udevice *dev, int pingval, int *pingret) 80 { 81 const struct test_ops *ops = device_get_ops(dev); 82 83 if (!ops->ping) 84 return -ENOSYS; 85 86 return ops->ping(dev, pingval, pingret); 87 } 88 89 UCLASS_DRIVER(testfdt) = { 90 .name = "testfdt", 91 .id = UCLASS_TEST_FDT, 92 }; 93 94 /* Test that FDT-based binding works correctly */ 95 static int dm_test_fdt(struct dm_test_state *dms) 96 { 97 const int num_drivers = 4; 98 struct udevice *dev; 99 struct uclass *uc; 100 int ret; 101 int i; 102 103 ret = dm_scan_fdt(gd->fdt_blob, false); 104 ut_assert(!ret); 105 106 ret = uclass_get(UCLASS_TEST_FDT, &uc); 107 ut_assert(!ret); 108 109 /* These are num_drivers compatible root-level device tree nodes */ 110 ut_asserteq(num_drivers, list_count_items(&uc->dev_head)); 111 112 /* Each should have no platdata / priv */ 113 for (i = 0; i < num_drivers; i++) { 114 ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev); 115 ut_assert(!ret); 116 ut_assert(!dev_get_priv(dev)); 117 ut_assert(!dev->platdata); 118 } 119 120 /* 121 * Now check that the ping adds are what we expect. This is using the 122 * ping-add property in each node. 123 */ 124 for (i = 0; i < num_drivers; i++) { 125 uint32_t base; 126 127 ret = uclass_get_device(UCLASS_TEST_FDT, i, &dev); 128 ut_assert(!ret); 129 130 /* 131 * Get the 'ping-expect' property, which tells us what the 132 * ping add should be. We don't use the platdata because we 133 * want to test the code that sets that up 134 * (testfdt_drv_probe()). 135 */ 136 base = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, 137 "ping-expect"); 138 debug("dev=%d, base=%d: %s\n", i, base, 139 fdt_get_name(gd->fdt_blob, dev->of_offset, NULL)); 140 141 ut_assert(!dm_check_operations(dms, dev, base, 142 dev_get_priv(dev))); 143 } 144 145 return 0; 146 } 147 DM_TEST(dm_test_fdt, 0); 148 149 static int dm_test_fdt_pre_reloc(struct dm_test_state *dms) 150 { 151 struct uclass *uc; 152 int ret; 153 154 ret = dm_scan_fdt(gd->fdt_blob, true); 155 ut_assert(!ret); 156 157 ret = uclass_get(UCLASS_TEST_FDT, &uc); 158 ut_assert(!ret); 159 160 /* These is only one pre-reloc device */ 161 ut_asserteq(1, list_count_items(&uc->dev_head)); 162 163 return 0; 164 } 165 DM_TEST(dm_test_fdt_pre_reloc, 0); 166 167 /* Test that sequence numbers are allocated properly */ 168 static int dm_test_fdt_uclass_seq(struct dm_test_state *dms) 169 { 170 struct udevice *dev; 171 172 /* A few basic santiy tests */ 173 ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev)); 174 ut_asserteq_str("b-test", dev->name); 175 176 ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 0, true, &dev)); 177 ut_asserteq_str("a-test", dev->name); 178 179 ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5, 180 true, &dev)); 181 ut_asserteq_ptr(NULL, dev); 182 183 /* Test aliases */ 184 ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 6, &dev)); 185 ut_asserteq_str("e-test", dev->name); 186 187 ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 7, 188 true, &dev)); 189 190 /* Note that c-test is not probed since it is not a top-level node */ 191 ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 3, &dev)); 192 ut_asserteq_str("b-test", dev->name); 193 194 /* 195 * d-test wants sequence number 3 also, but it can't have it because 196 * b-test gets it first. 197 */ 198 ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 2, &dev)); 199 ut_asserteq_str("d-test", dev->name); 200 201 /* d-test actually gets 0 */ 202 ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 0, &dev)); 203 ut_asserteq_str("d-test", dev->name); 204 205 /* initially no one wants seq 1 */ 206 ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, 207 &dev)); 208 ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev)); 209 ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev)); 210 211 /* But now that it is probed, we can find it */ 212 ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev)); 213 ut_asserteq_str("a-test", dev->name); 214 215 return 0; 216 } 217 DM_TEST(dm_test_fdt_uclass_seq, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 218 219 /* Test that we can find a device by device tree offset */ 220 static int dm_test_fdt_offset(struct dm_test_state *dms) 221 { 222 const void *blob = gd->fdt_blob; 223 struct udevice *dev; 224 int node; 225 226 node = fdt_path_offset(blob, "/e-test"); 227 ut_assert(node > 0); 228 ut_assertok(uclass_get_device_by_of_offset(UCLASS_TEST_FDT, node, 229 &dev)); 230 ut_asserteq_str("e-test", dev->name); 231 232 /* This node should not be bound */ 233 node = fdt_path_offset(blob, "/junk"); 234 ut_assert(node > 0); 235 ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT, 236 node, &dev)); 237 238 /* This is not a top level node so should not be probed */ 239 node = fdt_path_offset(blob, "/some-bus/c-test"); 240 ut_assert(node > 0); 241 ut_asserteq(-ENODEV, uclass_get_device_by_of_offset(UCLASS_TEST_FDT, 242 node, &dev)); 243 244 return 0; 245 } 246 247 DM_TEST(dm_test_fdt_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 248