]>
Commit | Line | Data |
---|---|---|
f50cc952 SG |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Tests for ACPI table generation | |
4 | * | |
5 | * Copyright 2019 Google LLC | |
6 | * Written by Simon Glass <sjg@chromium.org> | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
0b885bcf | 10 | #include <console.h> |
f50cc952 | 11 | #include <dm.h> |
7e586f69 | 12 | #include <malloc.h> |
29b35112 | 13 | #include <mapmem.h> |
7e586f69 | 14 | #include <tables_csum.h> |
1e4d965b | 15 | #include <version_string.h> |
b5183172 | 16 | #include <acpi/acpigen.h> |
1361a53c | 17 | #include <acpi/acpi_device.h> |
91fe8b79 | 18 | #include <acpi/acpi_table.h> |
401d1c4f | 19 | #include <asm/global_data.h> |
f50cc952 SG |
20 | #include <dm/acpi.h> |
21 | #include <dm/test.h> | |
22 | #include <test/ut.h> | |
82659cc9 | 23 | #include "acpi.h" |
f50cc952 | 24 | |
93f7f827 SG |
25 | #define BUF_SIZE 4096 |
26 | ||
1e4d965b SG |
27 | #define OEM_REVISION ((((version_num / 1000) % 10) << 28) | \ |
28 | (((version_num / 100) % 10) << 24) | \ | |
29 | (((version_num / 10) % 10) << 20) | \ | |
30 | ((version_num % 10) << 16) | \ | |
31 | (((version_num_patch / 10) % 10) << 12) | \ | |
32 | ((version_num_patch % 10) << 8) | \ | |
a3423b3f T |
33 | 0x01) |
34 | ||
1361a53c | 35 | /** |
8a8d24bd | 36 | * struct testacpi_plat - Platform data for the test ACPI device |
1361a53c SG |
37 | * |
38 | * @no_name: true to emit an empty ACPI name from testacpi_get_name() | |
39 | * @return_error: true to return an error instead of a name | |
40 | */ | |
8a8d24bd | 41 | struct testacpi_plat { |
1361a53c SG |
42 | bool return_error; |
43 | bool no_name; | |
44 | }; | |
45 | ||
cc1f8c39 SG |
46 | /** |
47 | * setup_ctx_and_base_tables() - Set up context along with RSDP, RSDT and XSDT | |
48 | * | |
49 | * Set up the context with the given start position. Some basic tables are | |
50 | * always needed, so set them up as well. | |
51 | * | |
52 | * @ctx: Context to set up | |
53 | */ | |
94ba15a3 SG |
54 | static int setup_ctx_and_base_tables(struct unit_test_state *uts, |
55 | struct acpi_ctx *ctx, ulong start) | |
cc1f8c39 | 56 | { |
94ba15a3 SG |
57 | struct acpi_writer *entry = ACPI_WRITER_GET(0base); |
58 | ||
cc1f8c39 | 59 | acpi_setup_ctx(ctx, start); |
94ba15a3 SG |
60 | |
61 | ctx->tab_start = ctx->current; | |
62 | ut_assertok(acpi_write_one(ctx, entry)); | |
cc1f8c39 SG |
63 | |
64 | return 0; | |
65 | } | |
66 | ||
93f7f827 SG |
67 | static int testacpi_write_tables(const struct udevice *dev, |
68 | struct acpi_ctx *ctx) | |
69 | { | |
70 | struct acpi_dmar *dmar; | |
29b35112 | 71 | int ret; |
93f7f827 SG |
72 | |
73 | dmar = (struct acpi_dmar *)ctx->current; | |
74 | acpi_create_dmar(dmar, DMAR_INTR_REMAP); | |
75 | ctx->current += sizeof(struct acpi_dmar); | |
29b35112 SG |
76 | ret = acpi_add_table(ctx, dmar); |
77 | if (ret) | |
78 | return log_msg_ret("add", ret); | |
93f7f827 SG |
79 | |
80 | return 0; | |
81 | } | |
f50cc952 SG |
82 | |
83 | static int testacpi_get_name(const struct udevice *dev, char *out_name) | |
84 | { | |
8a8d24bd | 85 | struct testacpi_plat *plat = dev_get_plat(dev); |
1361a53c SG |
86 | |
87 | if (plat->return_error) | |
88 | return -EINVAL; | |
89 | if (plat->no_name) { | |
90 | *out_name = '\0'; | |
91 | return 0; | |
92 | } | |
93 | if (device_get_uclass_id(dev->parent) == UCLASS_TEST_ACPI) | |
94 | return acpi_copy_name(out_name, ACPI_TEST_CHILD_NAME); | |
95 | else | |
96 | return acpi_copy_name(out_name, ACPI_TEST_DEV_NAME); | |
f50cc952 SG |
97 | } |
98 | ||
b5183172 SG |
99 | static int testacpi_fill_ssdt(const struct udevice *dev, struct acpi_ctx *ctx) |
100 | { | |
101 | const char *data; | |
102 | ||
103 | data = dev_read_string(dev, "acpi-ssdt-test-data"); | |
104 | if (data) { | |
105 | while (*data) | |
106 | acpigen_emit_byte(ctx, *data++); | |
107 | } | |
108 | ||
109 | return 0; | |
110 | } | |
111 | ||
01694589 SG |
112 | static int testacpi_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) |
113 | { | |
114 | const char *data; | |
115 | ||
116 | data = dev_read_string(dev, "acpi-dsdt-test-data"); | |
117 | if (data) { | |
118 | while (*data) | |
119 | acpigen_emit_byte(ctx, *data++); | |
120 | } | |
121 | ||
122 | return 0; | |
123 | } | |
124 | ||
f50cc952 SG |
125 | struct acpi_ops testacpi_ops = { |
126 | .get_name = testacpi_get_name, | |
93f7f827 | 127 | .write_tables = testacpi_write_tables, |
b5183172 | 128 | .fill_ssdt = testacpi_fill_ssdt, |
01694589 | 129 | .inject_dsdt = testacpi_inject_dsdt, |
f50cc952 SG |
130 | }; |
131 | ||
132 | static const struct udevice_id testacpi_ids[] = { | |
133 | { .compatible = "denx,u-boot-acpi-test" }, | |
134 | { } | |
135 | }; | |
136 | ||
137 | U_BOOT_DRIVER(testacpi_drv) = { | |
138 | .name = "testacpi_drv", | |
139 | .of_match = testacpi_ids, | |
140 | .id = UCLASS_TEST_ACPI, | |
1361a53c | 141 | .bind = dm_scan_fdt_dev, |
8a8d24bd | 142 | .plat_auto = sizeof(struct testacpi_plat), |
f50cc952 SG |
143 | ACPI_OPS_PTR(&testacpi_ops) |
144 | }; | |
145 | ||
146 | UCLASS_DRIVER(testacpi) = { | |
147 | .name = "testacpi", | |
148 | .id = UCLASS_TEST_ACPI, | |
149 | }; | |
150 | ||
151 | /* Test ACPI get_name() */ | |
152 | static int dm_test_acpi_get_name(struct unit_test_state *uts) | |
153 | { | |
154 | char name[ACPI_NAME_MAX]; | |
d1e85308 | 155 | struct udevice *dev, *dev2, *i2c, *spi, *timer, *sound; |
fefac0b0 | 156 | struct udevice *pci, *root; |
f50cc952 | 157 | |
fefac0b0 | 158 | /* Test getting the name from the driver */ |
f50cc952 SG |
159 | ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev)); |
160 | ut_assertok(acpi_get_name(dev, name)); | |
161 | ut_asserteq_str(ACPI_TEST_DEV_NAME, name); | |
162 | ||
fefac0b0 SG |
163 | /* Test getting the name from the device tree */ |
164 | ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "a-test", | |
165 | &dev2)); | |
166 | ut_assertok(acpi_get_name(dev2, name)); | |
167 | ut_asserteq_str("GHIJ", name); | |
168 | ||
169 | /* Test getting the name from acpi_device_get_name() */ | |
c726fc01 | 170 | ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c)); |
fefac0b0 SG |
171 | ut_assertok(acpi_get_name(i2c, name)); |
172 | ut_asserteq_str("I2C0", name); | |
173 | ||
c726fc01 | 174 | ut_assertok(uclass_first_device_err(UCLASS_SPI, &spi)); |
fefac0b0 SG |
175 | ut_assertok(acpi_get_name(spi, name)); |
176 | ut_asserteq_str("SPI0", name); | |
177 | ||
fefac0b0 | 178 | /* ACPI doesn't know about the timer */ |
c726fc01 | 179 | ut_assertok(uclass_first_device_err(UCLASS_TIMER, &timer)); |
fefac0b0 SG |
180 | ut_asserteq(-ENOENT, acpi_get_name(timer, name)); |
181 | ||
182 | /* May as well test the rest of the cases */ | |
c726fc01 | 183 | ut_assertok(uclass_first_device_err(UCLASS_SOUND, &sound)); |
fefac0b0 SG |
184 | ut_assertok(acpi_get_name(sound, name)); |
185 | ut_asserteq_str("HDAS", name); | |
186 | ||
c726fc01 | 187 | ut_assertok(uclass_first_device_err(UCLASS_PCI, &pci)); |
fefac0b0 SG |
188 | ut_assertok(acpi_get_name(pci, name)); |
189 | ut_asserteq_str("PCI0", name); | |
190 | ||
c726fc01 | 191 | ut_assertok(uclass_first_device_err(UCLASS_ROOT, &root)); |
fefac0b0 SG |
192 | ut_assertok(acpi_get_name(root, name)); |
193 | ut_asserteq_str("\\_SB", name); | |
194 | ||
195 | /* Note that we don't have tests for acpi_name_from_id() */ | |
196 | ||
f50cc952 SG |
197 | return 0; |
198 | } | |
e180c2b1 | 199 | DM_TEST(dm_test_acpi_get_name, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
91fe8b79 SG |
200 | |
201 | /* Test acpi_get_table_revision() */ | |
202 | static int dm_test_acpi_get_table_revision(struct unit_test_state *uts) | |
203 | { | |
204 | ut_asserteq(1, acpi_get_table_revision(ACPITAB_MCFG)); | |
205 | ut_asserteq(2, acpi_get_table_revision(ACPITAB_RSDP)); | |
206 | ut_asserteq(4, acpi_get_table_revision(ACPITAB_TPM2)); | |
207 | ut_asserteq(-EINVAL, acpi_get_table_revision(ACPITAB_COUNT)); | |
208 | ||
209 | return 0; | |
210 | } | |
211 | DM_TEST(dm_test_acpi_get_table_revision, | |
e180c2b1 | 212 | UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
bfeb5d46 | 213 | |
bfeb5d46 SG |
214 | /* Test acpi_create_dmar() */ |
215 | static int dm_test_acpi_create_dmar(struct unit_test_state *uts) | |
216 | { | |
217 | struct acpi_dmar dmar; | |
331caeaf | 218 | struct udevice *cpu; |
bfeb5d46 | 219 | |
c726fc01 | 220 | ut_assertok(uclass_first_device_err(UCLASS_CPU, &cpu)); |
331caeaf | 221 | ut_assertnonnull(cpu); |
bfeb5d46 SG |
222 | ut_assertok(acpi_create_dmar(&dmar, DMAR_INTR_REMAP)); |
223 | ut_asserteq(DMAR_INTR_REMAP, dmar.flags); | |
5ebe790f MV |
224 | ut_asserteq((IS_ENABLED(CONFIG_PHYS_64BIT) ? 64 : 32) - 1, |
225 | dmar.host_address_width); | |
bfeb5d46 SG |
226 | |
227 | return 0; | |
228 | } | |
e180c2b1 | 229 | DM_TEST(dm_test_acpi_create_dmar, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
93f7f827 SG |
230 | |
231 | /* Test acpi_fill_header() */ | |
232 | static int dm_test_acpi_fill_header(struct unit_test_state *uts) | |
233 | { | |
234 | struct acpi_table_header hdr; | |
235 | ||
236 | /* Make sure these 5 fields are not changed */ | |
237 | hdr.length = 0x11; | |
238 | hdr.revision = 0x22; | |
239 | hdr.checksum = 0x33; | |
4735d03a | 240 | hdr.creator_revision = 0x44; |
93f7f827 SG |
241 | acpi_fill_header(&hdr, "ABCD"); |
242 | ||
243 | ut_asserteq_mem("ABCD", hdr.signature, sizeof(hdr.signature)); | |
244 | ut_asserteq(0x11, hdr.length); | |
245 | ut_asserteq(0x22, hdr.revision); | |
246 | ut_asserteq(0x33, hdr.checksum); | |
247 | ut_asserteq_mem(OEM_ID, hdr.oem_id, sizeof(hdr.oem_id)); | |
248 | ut_asserteq_mem(OEM_TABLE_ID, hdr.oem_table_id, | |
249 | sizeof(hdr.oem_table_id)); | |
a3423b3f | 250 | ut_asserteq(OEM_REVISION, hdr.oem_revision); |
4735d03a HS |
251 | ut_asserteq_mem(ASLC_ID, hdr.creator_id, sizeof(hdr.creator_id)); |
252 | ut_asserteq(0x44, hdr.creator_revision); | |
93f7f827 SG |
253 | |
254 | return 0; | |
255 | } | |
e180c2b1 | 256 | DM_TEST(dm_test_acpi_fill_header, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
93f7f827 SG |
257 | |
258 | /* Test ACPI write_tables() */ | |
259 | static int dm_test_acpi_write_tables(struct unit_test_state *uts) | |
260 | { | |
261 | struct acpi_dmar *dmar; | |
262 | struct acpi_ctx ctx; | |
cc1f8c39 | 263 | ulong addr; |
93f7f827 | 264 | void *buf; |
1361a53c | 265 | int i; |
93f7f827 SG |
266 | |
267 | buf = malloc(BUF_SIZE); | |
268 | ut_assertnonnull(buf); | |
cc1f8c39 | 269 | addr = map_to_sysmem(buf); |
93f7f827 | 270 | |
94ba15a3 | 271 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); |
29b35112 | 272 | dmar = ctx.current; |
93f7f827 | 273 | ut_assertok(acpi_write_dev_tables(&ctx)); |
93f7f827 SG |
274 | |
275 | /* | |
1361a53c SG |
276 | * We should have three dmar tables, one for each |
277 | * "denx,u-boot-acpi-test" device | |
93f7f827 | 278 | */ |
1361a53c | 279 | ut_asserteq_ptr(dmar + 3, ctx.current); |
93f7f827 | 280 | ut_asserteq(DMAR_INTR_REMAP, dmar->flags); |
5ebe790f MV |
281 | ut_asserteq((IS_ENABLED(CONFIG_PHYS_64BIT) ? 64 : 32) - 1, |
282 | dmar->host_address_width); | |
93f7f827 SG |
283 | |
284 | ut_asserteq(DMAR_INTR_REMAP, dmar[1].flags); | |
5ebe790f MV |
285 | ut_asserteq((IS_ENABLED(CONFIG_PHYS_64BIT) ? 64 : 32) - 1, |
286 | dmar[1].host_address_width); | |
93f7f827 | 287 | |
1361a53c | 288 | ut_asserteq(DMAR_INTR_REMAP, dmar[2].flags); |
5ebe790f MV |
289 | ut_asserteq((IS_ENABLED(CONFIG_PHYS_64BIT) ? 64 : 32) - 1, |
290 | dmar[2].host_address_width); | |
7e586f69 | 291 | |
1361a53c SG |
292 | /* Check that the pointers were added correctly */ |
293 | for (i = 0; i < 3; i++) { | |
a8efebe7 SG |
294 | ut_asserteq(nomap_to_sysmem(dmar + i), ctx.rsdt->entry[i]); |
295 | ut_asserteq(nomap_to_sysmem(dmar + i), ctx.xsdt->entry[i]); | |
1361a53c SG |
296 | } |
297 | ut_asserteq(0, ctx.rsdt->entry[3]); | |
298 | ut_asserteq(0, ctx.xsdt->entry[3]); | |
b38309b7 | 299 | |
93f7f827 SG |
300 | return 0; |
301 | } | |
e180c2b1 | 302 | DM_TEST(dm_test_acpi_write_tables, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
86e1778d SG |
303 | |
304 | /* Test basic ACPI functions */ | |
305 | static int dm_test_acpi_basic(struct unit_test_state *uts) | |
306 | { | |
307 | struct acpi_ctx ctx; | |
308 | ||
309 | /* Check align works */ | |
310 | ctx.current = (void *)5; | |
311 | acpi_align(&ctx); | |
312 | ut_asserteq_ptr((void *)16, ctx.current); | |
313 | ||
314 | /* Check that align does nothing if already aligned */ | |
315 | acpi_align(&ctx); | |
316 | ut_asserteq_ptr((void *)16, ctx.current); | |
317 | acpi_align64(&ctx); | |
318 | ut_asserteq_ptr((void *)64, ctx.current); | |
319 | acpi_align64(&ctx); | |
320 | ut_asserteq_ptr((void *)64, ctx.current); | |
321 | ||
322 | /* Check incrementing */ | |
323 | acpi_inc(&ctx, 3); | |
324 | ut_asserteq_ptr((void *)67, ctx.current); | |
325 | acpi_inc_align(&ctx, 3); | |
326 | ut_asserteq_ptr((void *)80, ctx.current); | |
327 | ||
328 | return 0; | |
329 | } | |
e180c2b1 | 330 | DM_TEST(dm_test_acpi_basic, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
7e586f69 | 331 | |
31c27eb8 | 332 | /* Test setup_ctx_and_base_tables */ |
5e3adc44 | 333 | static int dm_test_acpi_ctx_and_base_tables(struct unit_test_state *uts) |
7e586f69 SG |
334 | { |
335 | struct acpi_rsdp *rsdp; | |
336 | struct acpi_rsdt *rsdt; | |
337 | struct acpi_xsdt *xsdt; | |
338 | struct acpi_ctx ctx; | |
339 | void *buf, *end; | |
cc1f8c39 | 340 | ulong addr; |
7e586f69 SG |
341 | |
342 | /* | |
343 | * Use an unaligned address deliberately, by allocating an aligned | |
344 | * address and then adding 4 to it | |
345 | */ | |
346 | buf = memalign(64, BUF_SIZE); | |
347 | ut_assertnonnull(buf); | |
cc1f8c39 | 348 | addr = map_to_sysmem(buf); |
94ba15a3 | 349 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr + 4)); |
233f0e35 | 350 | ut_asserteq(map_to_sysmem(PTR_ALIGN(buf + 4, 16)), gd_acpi_start()); |
7e586f69 SG |
351 | |
352 | rsdp = buf + 16; | |
353 | ut_asserteq_ptr(rsdp, ctx.rsdp); | |
f91f366b | 354 | ut_asserteq_mem(RSDP_SIG, rsdp->signature, sizeof(rsdp->signature)); |
7e586f69 SG |
355 | ut_asserteq(sizeof(*rsdp), rsdp->length); |
356 | ut_assertok(table_compute_checksum(rsdp, 20)); | |
357 | ut_assertok(table_compute_checksum(rsdp, sizeof(*rsdp))); | |
358 | ||
359 | rsdt = PTR_ALIGN((void *)rsdp + sizeof(*rsdp), 16); | |
360 | ut_asserteq_ptr(rsdt, ctx.rsdt); | |
f91f366b | 361 | ut_asserteq_mem("RSDT", rsdt->header.signature, ACPI_NAME_LEN); |
7e586f69 SG |
362 | ut_asserteq(sizeof(*rsdt), rsdt->header.length); |
363 | ut_assertok(table_compute_checksum(rsdt, sizeof(*rsdt))); | |
364 | ||
365 | xsdt = PTR_ALIGN((void *)rsdt + sizeof(*rsdt), 16); | |
b38309b7 | 366 | ut_asserteq_ptr(xsdt, ctx.xsdt); |
f91f366b | 367 | ut_asserteq_mem("XSDT", xsdt->header.signature, ACPI_NAME_LEN); |
7e586f69 SG |
368 | ut_asserteq(sizeof(*xsdt), xsdt->header.length); |
369 | ut_assertok(table_compute_checksum(xsdt, sizeof(*xsdt))); | |
370 | ||
371 | end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64); | |
372 | ut_asserteq_ptr(end, ctx.current); | |
373 | ||
a8efebe7 SG |
374 | ut_asserteq(nomap_to_sysmem(rsdt), rsdp->rsdt_address); |
375 | ut_asserteq(nomap_to_sysmem(xsdt), rsdp->xsdt_address); | |
7e586f69 SG |
376 | |
377 | return 0; | |
378 | } | |
5e3adc44 | 379 | DM_TEST(dm_test_acpi_ctx_and_base_tables, |
e180c2b1 | 380 | UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
0b885bcf SG |
381 | |
382 | /* Test 'acpi list' command */ | |
383 | static int dm_test_acpi_cmd_list(struct unit_test_state *uts) | |
384 | { | |
385 | struct acpi_ctx ctx; | |
386 | ulong addr; | |
387 | void *buf; | |
388 | ||
389 | buf = memalign(16, BUF_SIZE); | |
390 | ut_assertnonnull(buf); | |
cc1f8c39 | 391 | addr = map_to_sysmem(buf); |
94ba15a3 | 392 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); |
0b885bcf SG |
393 | |
394 | ut_assertok(acpi_write_dev_tables(&ctx)); | |
395 | ||
396 | console_record_reset(); | |
397 | run_command("acpi list", 0); | |
36e3a1e9 HS |
398 | ut_assert_nextline("Name Base Size Detail"); |
399 | ut_assert_nextline("---- ---------------- ----- ----------------------------"); | |
400 | ut_assert_nextline("RSDP %16lx %5zx v02 U-BOOT", addr, | |
0b885bcf SG |
401 | sizeof(struct acpi_rsdp)); |
402 | addr = ALIGN(addr + sizeof(struct acpi_rsdp), 16); | |
36e3a1e9 | 403 | ut_assert_nextline("RSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", |
0b885bcf | 404 | addr, sizeof(struct acpi_table_header) + |
a3423b3f | 405 | 3 * sizeof(u32), OEM_REVISION); |
0b885bcf | 406 | addr = ALIGN(addr + sizeof(struct acpi_rsdt), 16); |
36e3a1e9 | 407 | ut_assert_nextline("XSDT %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", |
0b885bcf | 408 | addr, sizeof(struct acpi_table_header) + |
a3423b3f | 409 | 3 * sizeof(u64), OEM_REVISION); |
0b885bcf | 410 | addr = ALIGN(addr + sizeof(struct acpi_xsdt), 64); |
36e3a1e9 | 411 | ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", |
a3423b3f | 412 | addr, sizeof(struct acpi_dmar), OEM_REVISION); |
0b885bcf | 413 | addr = ALIGN(addr + sizeof(struct acpi_dmar), 16); |
36e3a1e9 | 414 | ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", |
a3423b3f | 415 | addr, sizeof(struct acpi_dmar), OEM_REVISION); |
1361a53c | 416 | addr = ALIGN(addr + sizeof(struct acpi_dmar), 16); |
36e3a1e9 | 417 | ut_assert_nextline("DMAR %16lx %5zx v01 U-BOOT U-BOOTBL %x INTL 0", |
a3423b3f | 418 | addr, sizeof(struct acpi_dmar), OEM_REVISION); |
0b885bcf SG |
419 | ut_assert_console_end(); |
420 | ||
421 | return 0; | |
422 | } | |
e180c2b1 | 423 | DM_TEST(dm_test_acpi_cmd_list, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
0b885bcf SG |
424 | |
425 | /* Test 'acpi dump' command */ | |
426 | static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) | |
427 | { | |
428 | struct acpi_ctx ctx; | |
429 | ulong addr; | |
430 | void *buf; | |
431 | ||
432 | buf = memalign(16, BUF_SIZE); | |
433 | ut_assertnonnull(buf); | |
cc1f8c39 | 434 | addr = map_to_sysmem(buf); |
94ba15a3 | 435 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); |
0b885bcf SG |
436 | |
437 | ut_assertok(acpi_write_dev_tables(&ctx)); | |
438 | ||
439 | /* First search for a non-existent table */ | |
440 | console_record_reset(); | |
441 | run_command("acpi dump rdst", 0); | |
442 | ut_assert_nextline("Table 'RDST' not found"); | |
443 | ut_assert_console_end(); | |
444 | ||
445 | /* Now a real table */ | |
446 | console_record_reset(); | |
447 | run_command("acpi dump dmar", 0); | |
a8efebe7 | 448 | addr = ALIGN(nomap_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64); |
36e3a1e9 | 449 | ut_assert_nextline("DMAR @ %16lx", addr); |
0b885bcf SG |
450 | ut_assert_nextlines_are_dump(0x30); |
451 | ut_assert_console_end(); | |
452 | ||
453 | return 0; | |
454 | } | |
e180c2b1 | 455 | DM_TEST(dm_test_acpi_cmd_dump, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
1361a53c SG |
456 | |
457 | /* Test acpi_device_path() */ | |
458 | static int dm_test_acpi_device_path(struct unit_test_state *uts) | |
459 | { | |
8a8d24bd | 460 | struct testacpi_plat *plat; |
1361a53c SG |
461 | char buf[ACPI_PATH_MAX]; |
462 | struct udevice *dev, *child; | |
463 | ||
464 | ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev)); | |
465 | ut_assertok(acpi_device_path(dev, buf, sizeof(buf))); | |
466 | ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME, buf); | |
467 | ||
468 | /* Test running out of space */ | |
469 | buf[5] = '\0'; | |
470 | ut_asserteq(-ENOSPC, acpi_device_path(dev, buf, 5)); | |
471 | ut_asserteq('\0', buf[5]); | |
472 | ||
473 | /* Test a three-component name */ | |
474 | ut_assertok(device_first_child_err(dev, &child)); | |
475 | ut_assertok(acpi_device_path(child, buf, sizeof(buf))); | |
476 | ut_asserteq_str("\\_SB." ACPI_TEST_DEV_NAME "." ACPI_TEST_CHILD_NAME, | |
477 | buf); | |
478 | ||
479 | /* Test handling of a device which doesn't produce a name */ | |
c69cda25 | 480 | plat = dev_get_plat(dev); |
1361a53c SG |
481 | plat->no_name = true; |
482 | ut_assertok(acpi_device_path(child, buf, sizeof(buf))); | |
483 | ut_asserteq_str("\\_SB." ACPI_TEST_CHILD_NAME, buf); | |
484 | ||
485 | /* Test handling of a device which returns an error */ | |
c69cda25 | 486 | plat = dev_get_plat(dev); |
1361a53c SG |
487 | plat->return_error = true; |
488 | ut_asserteq(-EINVAL, acpi_device_path(child, buf, sizeof(buf))); | |
489 | ||
490 | return 0; | |
491 | } | |
e180c2b1 | 492 | DM_TEST(dm_test_acpi_device_path, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
2715b362 SG |
493 | |
494 | /* Test acpi_device_status() */ | |
495 | static int dm_test_acpi_device_status(struct unit_test_state *uts) | |
496 | { | |
497 | struct udevice *dev; | |
498 | ||
499 | ut_assertok(uclass_first_device_err(UCLASS_TEST_ACPI, &dev)); | |
500 | ut_asserteq(ACPI_DSTATUS_ALL_ON, acpi_device_status(dev)); | |
501 | ||
502 | return 0; | |
503 | } | |
e180c2b1 | 504 | DM_TEST(dm_test_acpi_device_status, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
b5183172 SG |
505 | |
506 | /* Test acpi_fill_ssdt() */ | |
507 | static int dm_test_acpi_fill_ssdt(struct unit_test_state *uts) | |
508 | { | |
509 | struct acpi_ctx ctx; | |
510 | u8 *buf; | |
511 | ||
512 | buf = malloc(BUF_SIZE); | |
513 | ut_assertnonnull(buf); | |
514 | ||
18434aec | 515 | acpi_reset_items(); |
b5183172 SG |
516 | ctx.current = buf; |
517 | buf[4] = 'z'; /* sentinel */ | |
518 | ut_assertok(acpi_fill_ssdt(&ctx)); | |
519 | ||
0f7b111f SG |
520 | /* |
521 | * These values come from acpi-test2's acpi-ssdt-test-data property. | |
522 | * This device comes first because of u-boot,acpi-ssdt-order | |
523 | */ | |
524 | ut_asserteq('c', buf[0]); | |
525 | ut_asserteq('d', buf[1]); | |
b5183172 | 526 | |
0f7b111f SG |
527 | /* These values come from acpi-test's acpi-ssdt-test-data property */ |
528 | ut_asserteq('a', buf[2]); | |
529 | ut_asserteq('b', buf[3]); | |
b5183172 SG |
530 | |
531 | ut_asserteq('z', buf[4]); | |
532 | ||
533 | return 0; | |
534 | } | |
e180c2b1 | 535 | DM_TEST(dm_test_acpi_fill_ssdt, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
01694589 SG |
536 | |
537 | /* Test acpi_inject_dsdt() */ | |
538 | static int dm_test_acpi_inject_dsdt(struct unit_test_state *uts) | |
539 | { | |
540 | struct acpi_ctx ctx; | |
541 | u8 *buf; | |
542 | ||
543 | buf = malloc(BUF_SIZE); | |
544 | ut_assertnonnull(buf); | |
545 | ||
18434aec | 546 | acpi_reset_items(); |
01694589 SG |
547 | ctx.current = buf; |
548 | buf[4] = 'z'; /* sentinel */ | |
549 | ut_assertok(acpi_inject_dsdt(&ctx)); | |
550 | ||
551 | /* | |
552 | * These values come from acpi-test's acpi-dsdt-test-data property. | |
553 | * There is no u-boot,acpi-dsdt-order so device-tree order is used. | |
554 | */ | |
555 | ut_asserteq('h', buf[0]); | |
556 | ut_asserteq('i', buf[1]); | |
557 | ||
558 | /* These values come from acpi-test's acpi-dsdt-test-data property */ | |
559 | ut_asserteq('j', buf[2]); | |
560 | ut_asserteq('k', buf[3]); | |
561 | ||
562 | ut_asserteq('z', buf[4]); | |
563 | ||
564 | return 0; | |
565 | } | |
e180c2b1 | 566 | DM_TEST(dm_test_acpi_inject_dsdt, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
a4f82089 SG |
567 | |
568 | /* Test 'acpi items' command */ | |
569 | static int dm_test_acpi_cmd_items(struct unit_test_state *uts) | |
570 | { | |
571 | struct acpi_ctx ctx; | |
a9246416 | 572 | ulong addr; |
a4f82089 SG |
573 | void *buf; |
574 | ||
575 | buf = malloc(BUF_SIZE); | |
576 | ut_assertnonnull(buf); | |
a9246416 | 577 | addr = map_to_sysmem(buf); |
a4f82089 | 578 | |
18434aec | 579 | acpi_reset_items(); |
a4f82089 SG |
580 | ctx.current = buf; |
581 | ut_assertok(acpi_fill_ssdt(&ctx)); | |
582 | console_record_reset(); | |
583 | run_command("acpi items", 0); | |
a9246416 SG |
584 | ut_assert_nextline("Seq Type Base Size Device/Writer"); |
585 | ut_assert_nextline("--- ----- -------- ---- -------------"); | |
586 | ut_assert_nextline(" 0 ssdt %8lx 2 acpi-test", addr); | |
587 | ut_assert_nextline(" 1 ssdt %8lx 2 acpi-test2", addr + 2); | |
a4f82089 SG |
588 | ut_assert_console_end(); |
589 | ||
18434aec | 590 | acpi_reset_items(); |
a4f82089 SG |
591 | ctx.current = buf; |
592 | ut_assertok(acpi_inject_dsdt(&ctx)); | |
593 | console_record_reset(); | |
594 | run_command("acpi items", 0); | |
a9246416 SG |
595 | ut_assert_nextlinen("Seq"); |
596 | ut_assert_nextlinen("---"); | |
597 | ut_assert_nextline(" 0 dsdt %8lx 2 acpi-test", addr); | |
598 | ut_assert_nextline(" 1 dsdt %8lx 2 acpi-test2", addr + 2); | |
a4f82089 SG |
599 | ut_assert_console_end(); |
600 | ||
601 | console_record_reset(); | |
602 | run_command("acpi items -d", 0); | |
a9246416 SG |
603 | ut_assert_nextlinen("Seq"); |
604 | ut_assert_nextlinen("---"); | |
605 | ut_assert_nextline(" 0 dsdt %8lx 2 acpi-test", addr); | |
a4f82089 SG |
606 | ut_assert_nextlines_are_dump(2); |
607 | ut_assert_nextline("%s", ""); | |
a9246416 | 608 | ut_assert_nextline(" 1 dsdt %8lx 2 acpi-test2", addr + 2); |
a4f82089 SG |
609 | ut_assert_nextlines_are_dump(2); |
610 | ut_assert_nextline("%s", ""); | |
611 | ut_assert_console_end(); | |
612 | ||
613 | return 0; | |
614 | } | |
e180c2b1 | 615 | DM_TEST(dm_test_acpi_cmd_items, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); |
29718414 SG |
616 | |
617 | /* Test 'acpi set' command */ | |
618 | static int dm_test_acpi_cmd_set(struct unit_test_state *uts) | |
619 | { | |
620 | struct acpi_ctx ctx; | |
621 | ulong addr; | |
622 | void *buf; | |
623 | ||
624 | gd_set_acpi_start(0); | |
625 | ||
626 | console_record_reset(); | |
627 | ut_asserteq(0, gd_acpi_start()); | |
628 | ut_assertok(run_command("acpi set", 0)); | |
629 | ut_assert_nextline("ACPI pointer: 0"); | |
630 | ||
631 | buf = memalign(16, BUF_SIZE); | |
632 | ut_assertnonnull(buf); | |
633 | addr = map_to_sysmem(buf); | |
634 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); | |
635 | ||
636 | ut_assertok(acpi_write_dev_tables(&ctx)); | |
637 | ||
638 | ut_assertok(run_command("acpi set", 0)); | |
639 | ut_assert_nextline("ACPI pointer: %lx", addr); | |
640 | ||
641 | ut_assertok(run_command("acpi set 0", 0)); | |
642 | ut_assert_nextline("Setting ACPI pointer to 0"); | |
643 | ut_asserteq(0, gd_acpi_start()); | |
644 | ||
645 | ut_assertok(run_commandf("acpi set %lx", addr)); | |
646 | ut_assert_nextline("Setting ACPI pointer to %lx", addr); | |
647 | ut_asserteq(addr, gd_acpi_start()); | |
648 | ||
649 | ut_assert_console_end(); | |
650 | ||
651 | return 0; | |
652 | } | |
653 | DM_TEST(dm_test_acpi_cmd_set, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); | |
0c2f6c31 HS |
654 | |
655 | /** | |
656 | * dm_test_write_test_table() - create test ACPI table | |
657 | * | |
658 | * Create an ACPI table TSTn, where n is given by @index. | |
659 | * | |
660 | * @ctx: ACPI table writing context | |
661 | * @index: table index | |
662 | * Return: generated table | |
663 | */ | |
664 | static struct acpi_table_header | |
665 | *dm_test_write_test_table(struct acpi_ctx *ctx, int index) | |
666 | { | |
667 | struct acpi_table_header *tbl = ctx->current; | |
668 | char signature[5]; | |
669 | ||
670 | snprintf(signature, sizeof(signature), "TST%1d", index); | |
671 | memset(tbl, 0, sizeof(*tbl)); | |
672 | acpi_fill_header(tbl, signature); | |
673 | acpi_inc(ctx, sizeof(struct acpi_table_header)); | |
674 | tbl->length = (u8 *)ctx->current - (u8 *)tbl; | |
675 | tbl->checksum = table_compute_checksum(tbl, tbl->length); | |
676 | acpi_add_table(ctx, tbl); | |
677 | ||
678 | return tbl; | |
679 | } | |
680 | ||
681 | /* Test acpi_find_table() */ | |
682 | static int dm_test_acpi_find_table(struct unit_test_state *uts) | |
683 | { | |
684 | struct acpi_ctx ctx; | |
685 | ulong acpi_start, addr; | |
686 | void *buf; | |
687 | struct acpi_table_header *table, *table1, *table2, *table3; | |
688 | struct acpi_rsdp *rsdp; | |
689 | ulong rsdt; | |
690 | ulong xsdt; | |
691 | ||
692 | /* Keep reference to original ACPI tables */ | |
693 | acpi_start = gd_acpi_start(); | |
694 | ||
695 | /* Setup new ACPI tables */ | |
696 | buf = memalign(16, BUF_SIZE); | |
697 | ut_assertnonnull(buf); | |
698 | addr = map_to_sysmem(buf); | |
699 | ut_assertok(setup_ctx_and_base_tables(uts, &ctx, addr)); | |
700 | table3 = dm_test_write_test_table(&ctx, 3); | |
701 | table1 = dm_test_write_test_table(&ctx, 1); | |
702 | table2 = dm_test_write_test_table(&ctx, 2); | |
703 | ||
704 | /* Retrieve RSDP, RSDT, XSDT */ | |
705 | rsdp = map_sysmem(gd_acpi_start(), 0); | |
706 | ut_assertnonnull(rsdp); | |
707 | rsdt = rsdp->rsdt_address; | |
708 | ut_assert(rsdt); | |
709 | xsdt = rsdp->xsdt_address; | |
710 | ut_assert(xsdt); | |
711 | ||
712 | /* Find with both RSDT and XSDT */ | |
713 | table = acpi_find_table("TST1"); | |
714 | ut_asserteq_ptr(table1, table); | |
715 | ut_asserteq_strn("TST1", table->signature); | |
716 | table = acpi_find_table("TST2"); | |
717 | ut_asserteq_ptr(table2, table); | |
718 | ut_asserteq_strn("TST2", table->signature); | |
719 | table = acpi_find_table("TST3"); | |
720 | ut_asserteq_ptr(table3, table); | |
721 | ut_asserteq_strn("TST3", table->signature); | |
722 | ||
723 | /* Find with XSDT only */ | |
724 | rsdp->rsdt_address = 0; | |
725 | table = acpi_find_table("TST1"); | |
726 | ut_asserteq_ptr(table1, table); | |
727 | table = acpi_find_table("TST2"); | |
728 | ut_asserteq_ptr(table2, table); | |
729 | table = acpi_find_table("TST3"); | |
730 | ut_asserteq_ptr(table3, table); | |
731 | rsdp->rsdt_address = rsdt; | |
732 | ||
733 | /* Find with RSDT only */ | |
734 | rsdp->xsdt_address = 0; | |
735 | table = acpi_find_table("TST1"); | |
736 | ut_asserteq_ptr(table1, table); | |
737 | table = acpi_find_table("TST2"); | |
738 | ut_asserteq_ptr(table2, table); | |
739 | table = acpi_find_table("TST3"); | |
740 | ut_asserteq_ptr(table3, table); | |
741 | rsdp->xsdt_address = xsdt; | |
742 | ||
743 | /* Restore previous ACPI tables */ | |
744 | gd_set_acpi_start(acpi_start); | |
745 | free(buf); | |
746 | ||
747 | return 0; | |
748 | } | |
749 | DM_TEST(dm_test_acpi_find_table, 0); | |
bda020e7 HS |
750 | |
751 | /* Test offsets in RSDT, XSDT */ | |
752 | static int dm_test_acpi_offsets(struct unit_test_state *uts) | |
753 | { | |
754 | ut_asserteq(36, offsetof(struct acpi_rsdt, entry)); | |
755 | ut_asserteq(36, offsetof(struct acpi_xsdt, entry)); | |
756 | ||
757 | return 0; | |
758 | } | |
759 | DM_TEST(dm_test_acpi_offsets, 0); |