1// SPDX-License-Identifier: GPL-2.0+ 2 3#include <clk.h> 4#include <dm.h> 5#include <dt-structs.h> 6#include <irq.h> 7#include <dm/test.h> 8#include <test/test.h> 9#include <test/ut.h> 10#include <asm-generic/gpio.h> 11#include <asm/global_data.h> 12 13/* Test that we can find a device using of-platdata */ 14static int dm_test_of_plat_base(struct unit_test_state *uts) 15{ 16 struct udevice *dev; 17 18 ut_assertok(uclass_first_device_err(UCLASS_SERIAL, &dev)); 19 ut_asserteq_str("sandbox_serial", dev->name); 20 21 return 0; 22} 23DM_TEST(dm_test_of_plat_base, UT_TESTF_SCAN_PDATA); 24 25/* Test that we can read properties from a device */ 26static int dm_test_of_plat_props(struct unit_test_state *uts) 27{ 28 struct dtd_sandbox_spl_test *plat; 29 struct udevice *dev; 30 int i; 31 32 ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_spl_test", 33 &dev)); 34 35 plat = dev_get_plat(dev); 36 ut_assert(plat->boolval); 37 ut_asserteq(1, plat->intval); 38 ut_asserteq(3, ARRAY_SIZE(plat->intarray)); 39 ut_asserteq(2, plat->intarray[0]); 40 ut_asserteq(3, plat->intarray[1]); 41 ut_asserteq(4, plat->intarray[2]); 42 ut_asserteq(5, plat->byteval); 43 ut_asserteq(1, ARRAY_SIZE(plat->maybe_empty_int)); 44 ut_asserteq(0, plat->maybe_empty_int[0]); 45 ut_asserteq(3, ARRAY_SIZE(plat->bytearray)); 46 ut_asserteq(6, plat->bytearray[0]); 47 ut_asserteq(0, plat->bytearray[1]); 48 ut_asserteq(0, plat->bytearray[2]); 49 ut_asserteq(9, ARRAY_SIZE(plat->longbytearray)); 50 for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++) 51 ut_asserteq(9 + i, plat->longbytearray[i]); 52 ut_asserteq_str("message", plat->stringval); 53 ut_asserteq(3, ARRAY_SIZE(plat->stringarray)); 54 ut_asserteq_str("multi-word", plat->stringarray[0]); 55 ut_asserteq_str("message", plat->stringarray[1]); 56 ut_asserteq_str("", plat->stringarray[2]); 57 58 ut_assertok(uclass_next_device_err(&dev)); 59 plat = dev_get_plat(dev); 60 ut_assert(!plat->boolval); 61 ut_asserteq(3, plat->intval); 62 ut_asserteq(5, plat->intarray[0]); 63 ut_asserteq(0, plat->intarray[1]); 64 ut_asserteq(0, plat->intarray[2]); 65 ut_asserteq(8, plat->byteval); 66 ut_asserteq(3, ARRAY_SIZE(plat->bytearray)); 67 ut_asserteq(1, plat->bytearray[0]); 68 ut_asserteq(0x23, plat->bytearray[1]); 69 ut_asserteq(0x34, plat->bytearray[2]); 70 for (i = 0; i < ARRAY_SIZE(plat->longbytearray); i++) 71 ut_asserteq(i < 4 ? 9 + i : 0, plat->longbytearray[i]); 72 ut_asserteq_str("message2", plat->stringval); 73 ut_asserteq_str("another", plat->stringarray[0]); 74 ut_asserteq_str("multi-word", plat->stringarray[1]); 75 ut_asserteq_str("message", plat->stringarray[2]); 76 77 ut_assertok(uclass_next_device_err(&dev)); 78 plat = dev_get_plat(dev); 79 ut_assert(!plat->boolval); 80 ut_asserteq_str("one", plat->stringarray[0]); 81 ut_asserteq_str("", plat->stringarray[1]); 82 ut_asserteq_str("", plat->stringarray[2]); 83 ut_asserteq(1, plat->maybe_empty_int[0]); 84 85 ut_assertok(uclass_next_device_err(&dev)); 86 plat = dev_get_plat(dev); 87 ut_assert(!plat->boolval); 88 ut_asserteq_str("spl", plat->stringarray[0]); 89 90 ut_asserteq(-ENODEV, uclass_next_device_err(&dev)); 91 92 return 0; 93} 94DM_TEST(dm_test_of_plat_props, UT_TESTF_SCAN_PDATA); 95 96/* 97 * find_driver_info - recursively find the driver_info for a device 98 * 99 * This sets found[idx] to true when it finds the driver_info record for a 100 * device, where idx is the index in the driver_info linker list. 101 * 102 * @uts: Test state 103 * @parent: Parent to search 104 * @found: bool array to update 105 * Return: 0 if OK, non-zero on error 106 */ 107static int find_driver_info(struct unit_test_state *uts, struct udevice *parent, 108 bool found[]) 109{ 110 struct udevice *dev; 111 112 /* If not the root device, find the entry that caused it to be bound */ 113 if (parent->parent) { 114 const int n_ents = 115 ll_entry_count(struct driver_info, driver_info); 116 int idx = -1; 117 int i; 118 119 for (i = 0; i < n_ents; i++) { 120 const struct driver_rt *drt = gd_dm_driver_rt() + i; 121 122 if (drt->dev == parent) { 123 idx = i; 124 found[idx] = true; 125 break; 126 } 127 } 128 129 ut_assert(idx != -1); 130 } 131 132 device_foreach_child(dev, parent) { 133 int ret; 134 135 ret = find_driver_info(uts, dev, found); 136 if (ret < 0) 137 return ret; 138 } 139 140 return 0; 141} 142 143/* Check that every device is recorded in its driver_info struct */ 144static int dm_test_of_plat_dev(struct unit_test_state *uts) 145{ 146 const int n_ents = ll_entry_count(struct driver_info, driver_info); 147 bool found[n_ents]; 148 uint i; 149 150 /* Skip this test if there is no platform data */ 151 if (!CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) 152 return -EAGAIN; 153 154 /* Record the indexes that are found */ 155 memset(found, '\0', sizeof(found)); 156 ut_assertok(find_driver_info(uts, gd->dm_root, found)); 157 158 /* Make sure that the driver entries without devices have no ->dev */ 159 for (i = 0; i < n_ents; i++) { 160 const struct driver_rt *drt = gd_dm_driver_rt() + i; 161 struct udevice *dev; 162 163 if (found[i]) { 164 /* Make sure we can find it */ 165 ut_assertnonnull(drt->dev); 166 ut_assertok(device_get_by_ofplat_idx(i, &dev)); 167 ut_asserteq_ptr(dev, drt->dev); 168 } else { 169 ut_assertnull(drt->dev); 170 ut_asserteq(-ENOENT, device_get_by_ofplat_idx(i, &dev)); 171 } 172 } 173 174 return 0; 175} 176DM_TEST(dm_test_of_plat_dev, UT_TESTF_SCAN_PDATA); 177 178/* Test handling of phandles that point to other devices */ 179static int dm_test_of_plat_phandle(struct unit_test_state *uts) 180{ 181 struct dtd_sandbox_clk_test *plat; 182 struct udevice *dev, *clk; 183 184 ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev)); 185 ut_asserteq_str("sandbox_clk_test", dev->name); 186 plat = dev_get_plat(dev); 187 188 ut_assertok(device_get_by_ofplat_idx(plat->clocks[0].idx, &clk)); 189 ut_asserteq_str("sandbox_fixed_clock", clk->name); 190 191 ut_assertok(device_get_by_ofplat_idx(plat->clocks[1].idx, &clk)); 192 ut_asserteq_str("sandbox_clk", clk->name); 193 ut_asserteq(1, plat->clocks[1].arg[0]); 194 195 ut_assertok(device_get_by_ofplat_idx(plat->clocks[2].idx, &clk)); 196 ut_asserteq_str("sandbox_clk", clk->name); 197 ut_asserteq(0, plat->clocks[2].arg[0]); 198 199 ut_assertok(device_get_by_ofplat_idx(plat->clocks[3].idx, &clk)); 200 ut_asserteq_str("sandbox_clk", clk->name); 201 ut_asserteq(3, plat->clocks[3].arg[0]); 202 203 ut_assertok(device_get_by_ofplat_idx(plat->clocks[4].idx, &clk)); 204 ut_asserteq_str("sandbox_clk", clk->name); 205 ut_asserteq(2, plat->clocks[4].arg[0]); 206 207 return 0; 208} 209DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA); 210 211#if CONFIG_IS_ENABLED(OF_PLATDATA_PARENT) 212/* Test that device parents are correctly set up */ 213static int dm_test_of_plat_parent(struct unit_test_state *uts) 214{ 215 struct udevice *rtc, *i2c; 216 217 ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc)); 218 ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c)); 219 ut_asserteq_ptr(i2c, dev_get_parent(rtc)); 220 221 return 0; 222} 223DM_TEST(dm_test_of_plat_parent, UT_TESTF_SCAN_PDATA); 224#endif 225 226/* Test clocks with of-platdata */ 227static int dm_test_of_plat_clk(struct unit_test_state *uts) 228{ 229 struct dtd_sandbox_clk_test *plat; 230 struct udevice *dev; 231 struct clk clk; 232 233 ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev)); 234 ut_asserteq_str("sandbox_clk_test", dev->name); 235 plat = dev_get_plat(dev); 236 237 ut_assertok(clk_get_by_phandle(dev, &plat->clocks[0], &clk)); 238 ut_asserteq_str("sandbox_fixed_clock", clk.dev->name); 239 240 return 0; 241} 242DM_TEST(dm_test_of_plat_clk, UT_TESTF_SCAN_PDATA); 243 244/* Test irqs with of-platdata */ 245static int dm_test_of_plat_irq(struct unit_test_state *uts) 246{ 247 struct dtd_sandbox_irq_test *plat; 248 struct udevice *dev; 249 struct irq irq; 250 251 ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_irq_test", 252 &dev)); 253 plat = dev_get_plat(dev); 254 255 ut_assertok(irq_get_by_phandle(dev, &plat->interrupts_extended[0], 256 &irq)); 257 ut_asserteq_str("sandbox_irq", irq.dev->name); 258 259 return 0; 260} 261DM_TEST(dm_test_of_plat_irq, UT_TESTF_SCAN_PDATA); 262 263/* Test GPIOs with of-platdata */ 264static int dm_test_of_plat_gpio(struct unit_test_state *uts) 265{ 266 struct dtd_sandbox_gpio_test *plat; 267 struct udevice *dev; 268 struct gpio_desc desc; 269 270 ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_gpio_test", 271 &dev)); 272 plat = dev_get_plat(dev); 273 274 ut_assertok(gpio_request_by_phandle(dev, &plat->test_gpios[0], &desc, 275 GPIOD_IS_OUT)); 276 ut_asserteq_str("sandbox_gpio", desc.dev->name); 277 278 return 0; 279} 280DM_TEST(dm_test_of_plat_gpio, UT_TESTF_SCAN_PDATA); 281