| /* |
| * 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 |
| } |