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