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