]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
86075bab SG |
2 | /* |
3 | * Copyright (C) 2015 Google, Inc | |
86075bab SG |
4 | */ |
5 | ||
86075bab | 6 | #include <dm.h> |
f7ae49fc | 7 | #include <log.h> |
86075bab SG |
8 | #include <mapmem.h> |
9 | #include <regmap.h> | |
10 | #include <syscon.h> | |
0ced26a4 | 11 | #include <rand.h> |
752ed086 | 12 | #include <time.h> |
86075bab SG |
13 | #include <asm/test.h> |
14 | #include <dm/test.h> | |
0ced26a4 | 15 | #include <dm/devres.h> |
61b29b82 | 16 | #include <linux/err.h> |
0e1fad43 | 17 | #include <test/test.h> |
86075bab SG |
18 | #include <test/ut.h> |
19 | ||
86075bab SG |
20 | /* Base test of register maps */ |
21 | static int dm_test_regmap_base(struct unit_test_state *uts) | |
22 | { | |
23 | struct udevice *dev; | |
24 | struct regmap *map; | |
99552c34 | 25 | ofnode node; |
86075bab SG |
26 | int i; |
27 | ||
28 | ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); | |
29 | map = syscon_get_regmap(dev); | |
30 | ut_assertok_ptr(map); | |
31 | ut_asserteq(1, map->range_count); | |
8c1de5e0 | 32 | ut_asserteq(0x10, map->ranges[0].start); |
82744c20 | 33 | ut_asserteq(16, map->ranges[0].size); |
86075bab SG |
34 | ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0))); |
35 | ||
36 | ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev)); | |
37 | map = syscon_get_regmap(dev); | |
38 | ut_assertok_ptr(map); | |
39 | ut_asserteq(4, map->range_count); | |
8c1de5e0 | 40 | ut_asserteq(0x20, map->ranges[0].start); |
86075bab SG |
41 | for (i = 0; i < 4; i++) { |
42 | const unsigned long addr = 0x20 + 8 * i; | |
43 | ||
8c1de5e0 MY |
44 | ut_asserteq(addr, map->ranges[i].start); |
45 | ut_asserteq(5 + i, map->ranges[i].size); | |
86075bab SG |
46 | ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i))); |
47 | } | |
48 | ||
49 | /* Check that we can't pretend a different device is a syscon */ | |
50 | ut_assertok(uclass_get_device(UCLASS_I2C, 0, &dev)); | |
51 | map = syscon_get_regmap(dev); | |
52 | ut_asserteq_ptr(ERR_PTR(-ENOEXEC), map); | |
53 | ||
99552c34 MY |
54 | /* A different device can be a syscon by using Linux-compat API */ |
55 | node = ofnode_path("/syscon@2"); | |
56 | ut_assert(ofnode_valid(node)); | |
57 | ||
58 | map = syscon_node_to_regmap(node); | |
59 | ut_assertok_ptr(map); | |
60 | ut_asserteq(4, map->range_count); | |
61 | ut_asserteq(0x40, map->ranges[0].start); | |
62 | for (i = 0; i < 4; i++) { | |
63 | const unsigned long addr = 0x40 + 8 * i; | |
64 | ||
65 | ut_asserteq(addr, map->ranges[i].start); | |
66 | ut_asserteq(5 + i, map->ranges[i].size); | |
67 | ut_asserteq(addr, map_to_sysmem(regmap_get_range(map, i))); | |
68 | } | |
69 | ||
86075bab SG |
70 | return 0; |
71 | } | |
e180c2b1 | 72 | DM_TEST(dm_test_regmap_base, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
86075bab SG |
73 | |
74 | /* Test we can access a regmap through syscon */ | |
75 | static int dm_test_regmap_syscon(struct unit_test_state *uts) | |
76 | { | |
77 | struct regmap *map; | |
78 | ||
79 | map = syscon_get_regmap_by_driver_data(SYSCON0); | |
80 | ut_assertok_ptr(map); | |
81 | ut_asserteq(1, map->range_count); | |
82 | ||
83 | map = syscon_get_regmap_by_driver_data(SYSCON1); | |
84 | ut_assertok_ptr(map); | |
85 | ut_asserteq(4, map->range_count); | |
86 | ||
87 | map = syscon_get_regmap_by_driver_data(SYSCON_COUNT); | |
88 | ut_asserteq_ptr(ERR_PTR(-ENODEV), map); | |
89 | ||
90 | ut_asserteq(0x10, map_to_sysmem(syscon_get_first_range(SYSCON0))); | |
91 | ut_asserteq(0x20, map_to_sysmem(syscon_get_first_range(SYSCON1))); | |
92 | ut_asserteq_ptr(ERR_PTR(-ENODEV), | |
93 | syscon_get_first_range(SYSCON_COUNT)); | |
94 | ||
95 | return 0; | |
96 | } | |
97 | ||
e180c2b1 | 98 | DM_TEST(dm_test_regmap_syscon, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
e068512c NA |
99 | |
100 | /* Read/Write/Modify test */ | |
101 | static int dm_test_regmap_rw(struct unit_test_state *uts) | |
102 | { | |
103 | struct udevice *dev; | |
104 | struct regmap *map; | |
105 | uint reg; | |
106 | ||
2333dc47 | 107 | sandbox_set_enable_memio(true); |
e068512c NA |
108 | ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); |
109 | map = syscon_get_regmap(dev); | |
110 | ut_assertok_ptr(map); | |
111 | ||
112 | ut_assertok(regmap_write(map, 0, 0xcacafafa)); | |
2333dc47 | 113 | ut_assertok(regmap_write(map, 5, 0x55aa2211)); |
e068512c NA |
114 | |
115 | ut_assertok(regmap_read(map, 0, ®)); | |
2333dc47 JJH |
116 | ut_asserteq(0xcacafafa, reg); |
117 | ut_assertok(regmap_read(map, 5, ®)); | |
118 | ut_asserteq(0x55aa2211, reg); | |
e068512c | 119 | |
2333dc47 JJH |
120 | ut_assertok(regmap_read(map, 0, ®)); |
121 | ut_asserteq(0xcacafafa, reg); | |
e068512c | 122 | ut_assertok(regmap_update_bits(map, 0, 0xff00ff00, 0x55aa2211)); |
2333dc47 JJH |
123 | ut_assertok(regmap_read(map, 0, ®)); |
124 | ut_asserteq(0x55ca22fa, reg); | |
125 | ut_assertok(regmap_update_bits(map, 5, 0x00ff00ff, 0xcacafada)); | |
126 | ut_assertok(regmap_read(map, 5, ®)); | |
127 | ut_asserteq(0x55ca22da, reg); | |
e068512c NA |
128 | |
129 | return 0; | |
130 | } | |
131 | ||
e180c2b1 | 132 | DM_TEST(dm_test_regmap_rw, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
45ef7f55 MS |
133 | |
134 | /* Get/Set test */ | |
135 | static int dm_test_regmap_getset(struct unit_test_state *uts) | |
136 | { | |
137 | struct udevice *dev; | |
138 | struct regmap *map; | |
139 | uint reg; | |
140 | struct layout { | |
141 | u32 val0; | |
142 | u32 val1; | |
143 | u32 val2; | |
144 | u32 val3; | |
145 | }; | |
146 | ||
2333dc47 | 147 | sandbox_set_enable_memio(true); |
45ef7f55 MS |
148 | ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); |
149 | map = syscon_get_regmap(dev); | |
150 | ut_assertok_ptr(map); | |
151 | ||
152 | regmap_set(map, struct layout, val0, 0xcacafafa); | |
153 | regmap_set(map, struct layout, val3, 0x55aa2211); | |
154 | ||
155 | ut_assertok(regmap_get(map, struct layout, val0, ®)); | |
2333dc47 | 156 | ut_asserteq(0xcacafafa, reg); |
45ef7f55 | 157 | ut_assertok(regmap_get(map, struct layout, val3, ®)); |
2333dc47 | 158 | ut_asserteq(0x55aa2211, reg); |
45ef7f55 MS |
159 | |
160 | return 0; | |
161 | } | |
162 | ||
e180c2b1 | 163 | DM_TEST(dm_test_regmap_getset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
ebe3497c NA |
164 | |
165 | /* Read polling test */ | |
166 | static int dm_test_regmap_poll(struct unit_test_state *uts) | |
167 | { | |
168 | struct udevice *dev; | |
169 | struct regmap *map; | |
170 | uint reg; | |
171 | unsigned long start; | |
172 | ||
173 | ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev)); | |
174 | map = syscon_get_regmap(dev); | |
175 | ut_assertok_ptr(map); | |
176 | ||
177 | start = get_timer(0); | |
178 | ||
2333dc47 | 179 | ut_assertok(regmap_write(map, 0, 0x0)); |
ebe3497c | 180 | ut_asserteq(-ETIMEDOUT, |
df9cf1cc SG |
181 | regmap_read_poll_timeout_test(map, 0, reg, |
182 | (reg == 0xcacafafa), | |
183 | 1, 5 * CONFIG_SYS_HZ, | |
184 | 5 * CONFIG_SYS_HZ)); | |
ebe3497c NA |
185 | |
186 | ut_assert(get_timer(start) > (5 * CONFIG_SYS_HZ)); | |
187 | ||
188 | return 0; | |
189 | } | |
190 | ||
e180c2b1 | 191 | DM_TEST(dm_test_regmap_poll, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
0ced26a4 JJH |
192 | |
193 | struct regmaptest_priv { | |
194 | struct regmap *cfg_regmap; /* For testing regmap_config options. */ | |
195 | struct regmap *fld_regmap; /* For testing regmap fields. */ | |
196 | struct regmap_field **fields; | |
197 | }; | |
198 | ||
199 | static const struct reg_field field_cfgs[] = { | |
200 | { | |
201 | .reg = 0, | |
202 | .lsb = 0, | |
203 | .msb = 6, | |
204 | }, | |
205 | { | |
206 | .reg = 2, | |
207 | .lsb = 4, | |
208 | .msb = 12, | |
209 | }, | |
210 | { | |
211 | .reg = 2, | |
212 | .lsb = 12, | |
213 | .msb = 15, | |
214 | } | |
215 | }; | |
216 | ||
217 | #define REGMAP_TEST_BUF_START 0 | |
218 | #define REGMAP_TEST_BUF_SZ 5 | |
219 | ||
220 | static int remaptest_probe(struct udevice *dev) | |
221 | { | |
222 | struct regmaptest_priv *priv = dev_get_priv(dev); | |
223 | struct regmap *regmap; | |
224 | struct regmap_field *field; | |
225 | struct regmap_config cfg; | |
226 | int i; | |
227 | static const int n = ARRAY_SIZE(field_cfgs); | |
228 | ||
229 | /* | |
230 | * To exercise all the regmap config options, create a regmap that | |
231 | * points to a custom memory area instead of the one defined in device | |
232 | * tree. Use 2-byte elements. To allow directly indexing into the | |
233 | * elements, use an offset shift of 1. So, accessing offset 1 gets the | |
234 | * element at index 1 at memory location 2. | |
235 | * | |
236 | * REGMAP_TEST_BUF_SZ is the number of elements, so we need to multiply | |
237 | * it by 2 because r_size expects number of bytes. | |
238 | */ | |
239 | cfg.reg_offset_shift = 1; | |
240 | cfg.r_start = REGMAP_TEST_BUF_START; | |
241 | cfg.r_size = REGMAP_TEST_BUF_SZ * 2; | |
242 | cfg.width = REGMAP_SIZE_16; | |
243 | ||
244 | regmap = devm_regmap_init(dev, NULL, NULL, &cfg); | |
245 | if (IS_ERR(regmap)) | |
246 | return PTR_ERR(regmap); | |
247 | priv->cfg_regmap = regmap; | |
248 | ||
249 | memset(&cfg, 0, sizeof(struct regmap_config)); | |
250 | cfg.width = REGMAP_SIZE_16; | |
251 | ||
252 | regmap = devm_regmap_init(dev, NULL, NULL, &cfg); | |
253 | if (IS_ERR(regmap)) | |
254 | return PTR_ERR(regmap); | |
255 | priv->fld_regmap = regmap; | |
256 | ||
257 | priv->fields = devm_kzalloc(dev, sizeof(struct regmap_field *) * n, | |
258 | GFP_KERNEL); | |
259 | if (!priv->fields) | |
260 | return -ENOMEM; | |
261 | ||
262 | for (i = 0 ; i < n; i++) { | |
263 | field = devm_regmap_field_alloc(dev, priv->fld_regmap, | |
264 | field_cfgs[i]); | |
265 | if (IS_ERR(field)) | |
266 | return PTR_ERR(field); | |
267 | priv->fields[i] = field; | |
268 | } | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
273 | static const struct udevice_id regmaptest_ids[] = { | |
274 | { .compatible = "sandbox,regmap_test" }, | |
275 | { } | |
276 | }; | |
277 | ||
278 | U_BOOT_DRIVER(regmap_test) = { | |
279 | .name = "regmaptest_drv", | |
280 | .of_match = regmaptest_ids, | |
281 | .id = UCLASS_NOP, | |
282 | .probe = remaptest_probe, | |
41575d8e | 283 | .priv_auto = sizeof(struct regmaptest_priv), |
0ced26a4 JJH |
284 | }; |
285 | ||
286 | static int dm_test_devm_regmap(struct unit_test_state *uts) | |
287 | { | |
288 | int i = 0; | |
7f58feae | 289 | uint val; |
0ced26a4 JJH |
290 | u16 pattern[REGMAP_TEST_BUF_SZ]; |
291 | u16 *buffer; | |
292 | struct udevice *dev; | |
293 | struct regmaptest_priv *priv; | |
294 | ||
295 | sandbox_set_enable_memio(true); | |
296 | ||
297 | /* | |
298 | * Map the memory area the regmap should point to so we can make sure | |
299 | * the writes actually go to that location. | |
300 | */ | |
301 | buffer = map_physmem(REGMAP_TEST_BUF_START, | |
302 | REGMAP_TEST_BUF_SZ * 2, MAP_NOCACHE); | |
303 | ||
304 | ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0", | |
305 | &dev)); | |
306 | priv = dev_get_priv(dev); | |
307 | ||
0ced26a4 | 308 | for (i = 0; i < REGMAP_TEST_BUF_SZ; i++) { |
2177f924 | 309 | pattern[i] = i * 0x87654321; |
0ced26a4 JJH |
310 | ut_assertok(regmap_write(priv->cfg_regmap, i, pattern[i])); |
311 | } | |
312 | for (i = 0; i < REGMAP_TEST_BUF_SZ; i++) { | |
7f58feae | 313 | ut_assertok(regmap_read(priv->cfg_regmap, i, &val)); |
0ced26a4 JJH |
314 | ut_asserteq(val, buffer[i]); |
315 | ut_asserteq(val, pattern[i]); | |
316 | } | |
317 | ||
318 | ut_asserteq(-ERANGE, regmap_write(priv->cfg_regmap, REGMAP_TEST_BUF_SZ, | |
319 | val)); | |
320 | ut_asserteq(-ERANGE, regmap_read(priv->cfg_regmap, REGMAP_TEST_BUF_SZ, | |
7f58feae | 321 | &val)); |
0ced26a4 | 322 | ut_asserteq(-ERANGE, regmap_write(priv->cfg_regmap, -1, val)); |
7f58feae | 323 | ut_asserteq(-ERANGE, regmap_read(priv->cfg_regmap, -1, &val)); |
0ced26a4 JJH |
324 | |
325 | return 0; | |
326 | } | |
327 | DM_TEST(dm_test_devm_regmap, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); | |
328 | ||
329 | static int test_one_field(struct unit_test_state *uts, | |
330 | struct regmap *regmap, | |
331 | struct regmap_field *field, | |
332 | struct reg_field field_cfg) | |
333 | { | |
334 | int j; | |
335 | unsigned int val; | |
336 | int mask = (1 << (field_cfg.msb - field_cfg.lsb + 1)) - 1; | |
337 | int shift = field_cfg.lsb; | |
338 | ||
339 | ut_assertok(regmap_write(regmap, field_cfg.reg, 0)); | |
340 | ut_assertok(regmap_read(regmap, field_cfg.reg, &val)); | |
341 | ut_asserteq(0, val); | |
342 | ||
343 | for (j = 0; j <= mask; j++) { | |
344 | ut_assertok(regmap_field_write(field, j)); | |
345 | ut_assertok(regmap_field_read(field, &val)); | |
346 | ut_asserteq(j, val); | |
347 | ut_assertok(regmap_read(regmap, field_cfg.reg, &val)); | |
348 | ut_asserteq(j << shift, val); | |
349 | } | |
350 | ||
351 | ut_assertok(regmap_field_write(field, mask + 1)); | |
352 | ut_assertok(regmap_read(regmap, field_cfg.reg, &val)); | |
353 | ut_asserteq(0, val); | |
354 | ||
355 | ut_assertok(regmap_field_write(field, 0xFFFF)); | |
356 | ut_assertok(regmap_read(regmap, field_cfg.reg, &val)); | |
357 | ut_asserteq(mask << shift, val); | |
358 | ||
359 | ut_assertok(regmap_write(regmap, field_cfg.reg, 0xFFFF)); | |
360 | ut_assertok(regmap_field_write(field, 0)); | |
361 | ut_assertok(regmap_read(regmap, field_cfg.reg, &val)); | |
362 | ut_asserteq(0xFFFF & ~(mask << shift), val); | |
363 | return 0; | |
364 | } | |
365 | ||
366 | static int dm_test_devm_regmap_field(struct unit_test_state *uts) | |
367 | { | |
368 | int i, rc; | |
369 | struct udevice *dev; | |
370 | struct regmaptest_priv *priv; | |
371 | ||
372 | ut_assertok(uclass_get_device_by_name(UCLASS_NOP, "regmap-test_0", | |
373 | &dev)); | |
374 | priv = dev_get_priv(dev); | |
375 | ||
376 | sandbox_set_enable_memio(true); | |
377 | for (i = 0 ; i < ARRAY_SIZE(field_cfgs); i++) { | |
378 | rc = test_one_field(uts, priv->fld_regmap, priv->fields[i], | |
379 | field_cfgs[i]); | |
380 | if (rc) | |
381 | break; | |
382 | } | |
383 | ||
384 | return 0; | |
385 | } | |
386 | DM_TEST(dm_test_devm_regmap_field, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |