Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | /* * Copyright (c) 2020 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/ztest.h> #include <zephyr/device.h> #define DT_DRV_COMPAT fakedriver /* * Driver with a single MMIO region to manage */ struct foo_single_dev_data { DEVICE_MMIO_RAM; int baz; }; struct foo_single_dev_data foo0_data; struct foo_single_config_info { DEVICE_MMIO_ROM; }; const struct foo_single_config_info foo0_config = { DEVICE_MMIO_ROM_INIT(DT_DRV_INST(0)), }; int foo_single_init(const struct device *dev) { DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); return 0; } /* fake API pointer, we don't use it at all for this suite */ DEVICE_DEFINE(foo0, "foo0", foo_single_init, NULL, &foo0_data, &foo0_config, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, (void *)0xDEADBEEF); /** * @brief Test DEVICE_MMIO_* macros * * We show that we can make mapping calls and that the address returned by * DEVICE_MMIO_GET() is not NULL, indicating that the kernel mapped * stuff somewhere. * * We also perform some checks depending on configuration: * - If MMIO addresses are maintained in RAM, check that the ROM struct * was populated correctly. * - If MMIO addresses are maintained in ROM, check that the DTS info, * the ROM region, and the result of DEVICE_MMIO_GET() all * point to the same address. We show that no extra memory is used in * dev_data. * * @ingroup kernel_device_tests */ ZTEST(device, test_mmio_single) { struct z_device_mmio_rom *rom; const struct device *dev = device_get_binding("foo0"); mm_reg_t regs; zassert_not_null(dev, "null foo0"); regs = DEVICE_MMIO_GET(dev); rom = DEVICE_MMIO_ROM_PTR(dev); /* A sign that something didn't get initialized, shouldn't ever * be 0 */ zassert_not_equal(regs, 0, "NULL regs"); #ifdef DEVICE_MMIO_IS_IN_RAM /* The config info should just contain the addr/size from DTS. * The best we can check with 'regs' is that it's nonzero, as if * an MMU is enabled, the kernel chooses the virtual address to * place it at. We don't otherwise look at `regs`; other tests will * prove that k_map() actually works. */ zassert_equal(rom->phys_addr, DT_INST_REG_ADDR(0), "bad phys_addr"); zassert_equal(rom->size, DT_INST_REG_SIZE(0), "bad size"); #else /* Config info contains base address, which should be the base * address from DTS, and regs should have the same value. * In this configuration dev_data has nothing mmio-related in it */ zassert_equal(rom->addr, DT_INST_REG_ADDR(0), "bad addr"); zassert_equal(regs, rom->addr, "bad regs"); /* Just the baz member */ zassert_equal(sizeof(struct foo_single_dev_data), sizeof(int), "too big foo_single_dev_data"); #endif } /* * Driver with multiple MMIO regions to manage */ struct foo_mult_dev_data { int baz; DEVICE_MMIO_NAMED_RAM(corge); DEVICE_MMIO_NAMED_RAM(grault); }; struct foo_mult_dev_data foo12_data; struct foo_mult_config_info { DEVICE_MMIO_NAMED_ROM(corge); DEVICE_MMIO_NAMED_ROM(grault); }; const struct foo_mult_config_info foo12_config = { DEVICE_MMIO_NAMED_ROM_INIT(corge, DT_DRV_INST(1)), DEVICE_MMIO_NAMED_ROM_INIT(grault, DT_DRV_INST(2)) }; #define DEV_DATA(dev) ((struct foo_mult_dev_data *)((dev)->data)) #define DEV_CFG(dev) ((struct foo_mult_config_info *)((dev)->config)) int foo_mult_init(const struct device *dev) { DEVICE_MMIO_NAMED_MAP(dev, corge, K_MEM_CACHE_NONE); DEVICE_MMIO_NAMED_MAP(dev, grault, K_MEM_CACHE_NONE); return 0; } DEVICE_DEFINE(foo12, "foo12", foo_mult_init, NULL, &foo12_data, &foo12_config, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, (void *)0xDEADBEEF); /** * @brief Test DEVICE_MMIO_NAMED_* macros * * We show that we can make mapping calls and that the address returned by * DEVICE_MMIO_NAMED_GET() is not NULL, indicating that the kernel mapped * stuff somewhere. * * We show that this works for a device instance that has two named regions, * 'corge' and 'grault' that respectively come from DTS instances 1 and 2. * * We also perform some checks depending on configuration: * - If MMIO addresses are maintained in RAM, check that the ROM struct * was populated correctly. * - If MMIO addresses are maintained in ROM, check that the DTS info, * the ROM region, and the result of DEVICE_MMIO_NAMED_GET() all * point to the same address. We show that no extra memory is used in * dev_data. * * @ingroup kernel_device_tests */ ZTEST(device, test_mmio_multiple) { /* See comments for test_mmio_single */ const struct device *dev = device_get_binding("foo12"); mm_reg_t regs_corge, regs_grault; const struct z_device_mmio_rom *rom_corge, *rom_grault; zassert_not_null(dev, "null foo12"); regs_corge = DEVICE_MMIO_NAMED_GET(dev, corge); regs_grault = DEVICE_MMIO_NAMED_GET(dev, grault); rom_corge = DEVICE_MMIO_NAMED_ROM_PTR(dev, corge); rom_grault = DEVICE_MMIO_NAMED_ROM_PTR(dev, grault); zassert_not_equal(regs_corge, 0, "bad regs_corge"); zassert_not_equal(regs_grault, 0, "bad regs_grault"); #ifdef DEVICE_MMIO_IS_IN_RAM zassert_equal(rom_corge->phys_addr, DT_INST_REG_ADDR(1), "bad phys_addr (corge)"); zassert_equal(rom_corge->size, DT_INST_REG_SIZE(1), "bad size (corge)"); zassert_equal(rom_grault->phys_addr, DT_INST_REG_ADDR(2), "bad phys_addr (grault)"); zassert_equal(rom_grault->size, DT_INST_REG_SIZE(2), "bad size (grault)"); #else zassert_equal(rom_corge->addr, DT_INST_REG_ADDR(1), "bad addr (corge)"); zassert_equal(regs_corge, rom_corge->addr, "bad regs (corge)"); zassert_equal(rom_grault->addr, DT_INST_REG_ADDR(2), "bad addr (grault)"); zassert_equal(regs_grault, rom_grault->addr, "bad regs (grault)"); zassert_equal(sizeof(struct foo_mult_dev_data), sizeof(int), "too big foo_mult_dev_data"); #endif } /* * Not using driver model, toplevel definition */ DEVICE_MMIO_TOPLEVEL(foo3, DT_DRV_INST(3)); DEVICE_MMIO_TOPLEVEL_STATIC(foo4, DT_DRV_INST(4)); /** * @brief Test DEVICE_MMIO_TOPLEVEL_* macros * * We show that we can make mapping calls and that the address returned by * DEVICE_MMIO_TOPLEVEL_GET() is not NULL, indicating that the kernel mapped * stuff somewhere. * * We do this for two different MMIO toplevel instances; one declared * statically and one not. * * We also perform some checks depending on configuration: * - If MMIO addresses are maintained in RAM, check that the ROM struct * was populated correctly. * - If MMIO addresses are maintained in ROM, check that the DTS info, * the ROM region, and the result of DEVICE_MMIO_TOPLEVEL_GET() all * point to the same address * * @ingroup kernel_device_tests */ ZTEST(device, test_mmio_toplevel) { mm_reg_t regs_foo3, regs_foo4; const struct z_device_mmio_rom *rom_foo3, *rom_foo4; DEVICE_MMIO_TOPLEVEL_MAP(foo3, K_MEM_CACHE_NONE); DEVICE_MMIO_TOPLEVEL_MAP(foo4, K_MEM_CACHE_NONE); regs_foo3 = DEVICE_MMIO_TOPLEVEL_GET(foo3); regs_foo4 = DEVICE_MMIO_TOPLEVEL_GET(foo4); rom_foo3 = DEVICE_MMIO_TOPLEVEL_ROM_PTR(foo3); rom_foo4 = DEVICE_MMIO_TOPLEVEL_ROM_PTR(foo4); zassert_not_equal(regs_foo3, 0, "bad regs_corge"); zassert_not_equal(regs_foo4, 0, "bad regs_grault"); #ifdef DEVICE_MMIO_IS_IN_RAM zassert_equal(rom_foo3->phys_addr, DT_INST_REG_ADDR(3), "bad phys_addr (foo3)"); zassert_equal(rom_foo3->size, DT_INST_REG_SIZE(3), "bad size (foo3)"); zassert_equal(rom_foo4->phys_addr, DT_INST_REG_ADDR(4), "bad phys_addr (foo4)"); zassert_equal(rom_foo4->size, DT_INST_REG_SIZE(4), "bad size (foo4)"); #else zassert_equal(rom_foo3->addr, DT_INST_REG_ADDR(3), "bad addr (foo3)"); zassert_equal(regs_foo3, rom_foo3->addr, "bad regs (foo3)"); zassert_equal(rom_foo4->addr, DT_INST_REG_ADDR(4), "bad addr (foo4)"); zassert_equal(regs_foo4, rom_foo4->addr, "bad regs (foo4)"); #endif } /** * @brief device_map() test * * Show that device_map() populates a memory address. We don't do anything else; * tests for k_map() will prove that virtual memory mapping actually works. */ ZTEST(device, test_mmio_device_map) { #ifdef DEVICE_MMIO_IS_IN_RAM mm_reg_t regs = 0; device_map(®s, 0xF0000000, 0x1000, K_MEM_CACHE_NONE); zassert_not_equal(regs, 0, "bad regs"); #else ztest_test_skip(); #endif } |