blob: 038806004b555b58b8c771b10e4ce33a61cedbd5 [file] [log] [blame]
Simon Glassc993ff72020-07-07 13:11:56 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Tests for ACPI code generation via a device-property table
4 *
5 * Copyright 2019 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glassc993ff72020-07-07 13:11:56 -06009#include <dm.h>
Caleb Connolly29cab7c2024-08-30 13:34:37 +010010#include <u-boot/uuid.h>
Simon Glassc993ff72020-07-07 13:11:56 -060011#include <acpi/acpigen.h>
12#include <acpi/acpi_dp.h>
13#include <asm/unaligned.h>
14#include <dm/acpi.h>
15#include <dm/test.h>
16#include <test/ut.h>
17#include "acpi.h"
18
19/* Maximum size of the ACPI context needed for most tests */
20#define ACPI_CONTEXT_SIZE 500
21
22#define TEST_INT8 0x7d
23#define TEST_INT16 0x2345
24#define TEST_INT32 0x12345678
25#define TEST_INT64 0x4567890123456
26#define TEST_STR "testing acpi strings"
27#define TEST_REF "\\SB.I2C0.TPM2"
28#define EXPECT_REF "SB__I2C0TPM2"
29
30static int alloc_context(struct acpi_ctx **ctxp)
31{
32 return acpi_test_alloc_context_size(ctxp, ACPI_CONTEXT_SIZE);
33
34 return 0;
35}
36
37static void free_context(struct acpi_ctx **ctxp)
38{
39 free(*ctxp);
40 *ctxp = NULL;
41}
42
43/* Test emitting an empty table */
44static int dm_test_acpi_dp_new_table(struct unit_test_state *uts)
45{
46 struct acpi_ctx *ctx;
47 struct acpi_dp *dp;
48 u8 *ptr;
49
50 ut_assertok(alloc_context(&ctx));
51
52 dp = acpi_dp_new_table("FRED");
53 ut_assertnonnull(dp);
54
55 ptr = acpigen_get_current(ctx);
56 ut_assertok(acpi_dp_write(ctx, dp));
57 ut_asserteq(10, acpigen_get_current(ctx) - ptr);
58 ut_asserteq(NAME_OP, *(u8 *)ptr);
59 ut_asserteq_strn("FRED", (char *)ptr + 1);
60 ut_asserteq(PACKAGE_OP, ptr[5]);
61 ut_asserteq(4, acpi_test_get_length(ptr + 6));
62 ut_asserteq(0, ptr[9]);
63
64 free_context(&ctx);
65
66 return 0;
67}
68DM_TEST(dm_test_acpi_dp_new_table, 0);
69
70/* Test emitting an integer */
71static int dm_test_acpi_dp_int(struct unit_test_state *uts)
72{
73 struct acpi_ctx *ctx;
74 char uuid[UUID_STR_LEN + 1];
75 struct acpi_dp *dp;
76 u8 *ptr;
77
78 ut_assertok(alloc_context(&ctx));
79
80 dp = acpi_dp_new_table("FRED");
81 ut_assertnonnull(dp);
82 ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT32));
83
84 ptr = acpigen_get_current(ctx);
85 ut_assertok(acpi_dp_write(ctx, dp));
86 ut_asserteq(54, acpigen_get_current(ctx) - ptr);
87 ut_asserteq(NAME_OP, *(u8 *)ptr);
88 ut_asserteq_strn("FRED", (char *)ptr + 1);
89 ut_asserteq(PACKAGE_OP, ptr[5]);
90 ut_asserteq(48, acpi_test_get_length(ptr + 6));
91 ut_asserteq(2, ptr[9]);
92
93 /* UUID */
94 ut_asserteq(BUFFER_OP, ptr[10]);
95 ut_asserteq(22, acpi_test_get_length(ptr + 11));
96 ut_asserteq(WORD_PREFIX, ptr[14]);
97 ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
98 uuid_bin_to_str(ptr + 17, uuid, 1);
99 ut_asserteq_str(ACPI_DP_UUID, uuid);
100
101 /* Container package */
102 ut_asserteq(PACKAGE_OP, ptr[33]);
103 ut_asserteq(20, acpi_test_get_length(ptr + 34));
104 ut_asserteq(1, ptr[37]);
105
106 /* Package with name and (integer) value */
107 ut_asserteq(PACKAGE_OP, ptr[38]);
108 ut_asserteq(15, acpi_test_get_length(ptr + 39));
109 ut_asserteq(2, ptr[42]);
110 ut_asserteq(STRING_PREFIX, ptr[43]);
111 ut_asserteq_str("MARY", (char *)ptr + 44);
112
113 ut_asserteq(DWORD_PREFIX, ptr[49]);
114 ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 50)));
115
116 free_context(&ctx);
117
118 return 0;
119}
120DM_TEST(dm_test_acpi_dp_int, 0);
121
122/* Test emitting a 64-bit integer */
123static int dm_test_acpi_dp_int64(struct unit_test_state *uts)
124{
125 struct acpi_ctx *ctx;
126 struct acpi_dp *dp;
127 u8 *ptr;
128
129 ut_assertok(alloc_context(&ctx));
130
131 dp = acpi_dp_new_table("FRED");
132 ut_assertnonnull(dp);
133 ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT64));
134
135 ptr = acpigen_get_current(ctx);
136 ut_assertok(acpi_dp_write(ctx, dp));
137 ut_asserteq(58, acpigen_get_current(ctx) - ptr);
138
139 ut_asserteq(QWORD_PREFIX, ptr[49]);
140 ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 50)));
141
142 free_context(&ctx);
143
144 return 0;
145}
146DM_TEST(dm_test_acpi_dp_int64, 0);
147
148/* Test emitting a 16-bit integer */
149static int dm_test_acpi_dp_int16(struct unit_test_state *uts)
150{
151 struct acpi_ctx *ctx;
152 struct acpi_dp *dp;
153 u8 *ptr;
154
155 ut_assertok(alloc_context(&ctx));
156
157 dp = acpi_dp_new_table("FRED");
158 ut_assertnonnull(dp);
159 ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT16));
160
161 ptr = acpigen_get_current(ctx);
162 ut_assertok(acpi_dp_write(ctx, dp));
163 ut_asserteq(52, acpigen_get_current(ctx) - ptr);
164
165 ut_asserteq(WORD_PREFIX, ptr[49]);
166 ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 50)));
167
168 free_context(&ctx);
169
170 return 0;
171}
172DM_TEST(dm_test_acpi_dp_int16, 0);
173
174/* Test emitting a 8-bit integer */
175static int dm_test_acpi_dp_int8(struct unit_test_state *uts)
176{
177 struct acpi_ctx *ctx;
178 struct acpi_dp *dp;
179 u8 *ptr;
180
181 ut_assertok(alloc_context(&ctx));
182
183 dp = acpi_dp_new_table("FRED");
184 ut_assertnonnull(dp);
185 ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT8));
186
187 ptr = acpigen_get_current(ctx);
188 ut_assertok(acpi_dp_write(ctx, dp));
189 ut_asserteq(51, acpigen_get_current(ctx) - ptr);
190
191 ut_asserteq(BYTE_PREFIX, ptr[49]);
192 ut_asserteq(TEST_INT8, ptr[50]);
193
194 free_context(&ctx);
195
196 return 0;
197}
198DM_TEST(dm_test_acpi_dp_int8, 0);
199
200/* Test emitting multiple values */
201static int dm_test_acpi_dp_multiple(struct unit_test_state *uts)
202{
203 struct acpi_ctx *ctx;
204 struct acpi_dp *dp;
205 u8 *ptr;
206
207 ut_assertok(alloc_context(&ctx));
208
209 dp = acpi_dp_new_table("FRED");
210 ut_assertnonnull(dp);
211 ut_assertnonnull(acpi_dp_add_integer(dp, "int16", TEST_INT16));
212 ut_assertnonnull(acpi_dp_add_string(dp, "str", TEST_STR));
213 ut_assertnonnull(acpi_dp_add_reference(dp, "ref", TEST_REF));
214
215 ptr = acpigen_get_current(ctx);
216 ut_assertok(acpi_dp_write(ctx, dp));
217 ut_asserteq(110, acpigen_get_current(ctx) - ptr);
218
219 ut_asserteq(WORD_PREFIX, ptr[0x32]);
220 ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x33)));
221 ut_asserteq(STRING_PREFIX, ptr[0x3f]);
222 ut_asserteq_str(TEST_STR, (char *)ptr + 0x40);
223 ut_asserteq(ROOT_PREFIX, ptr[0x5f]);
224 ut_asserteq(MULTI_NAME_PREFIX, ptr[0x60]);
225 ut_asserteq(3, ptr[0x61]);
226 ut_asserteq_strn(EXPECT_REF, (char *)ptr + 0x62);
227
228 free_context(&ctx);
229
230 return 0;
231}
232DM_TEST(dm_test_acpi_dp_multiple, 0);
233
234/* Test emitting an array */
235static int dm_test_acpi_dp_array(struct unit_test_state *uts)
236{
237 struct acpi_ctx *ctx;
238 struct acpi_dp *dp;
239 u64 speed[4];
240 u8 *ptr;
241
242 ut_assertok(alloc_context(&ctx));
243
244 dp = acpi_dp_new_table("FRED");
245 ut_assertnonnull(dp);
246 speed[0] = TEST_INT8;
247 speed[1] = TEST_INT16;
248 speed[2] = TEST_INT32;
249 speed[3] = TEST_INT64;
250 ut_assertnonnull(acpi_dp_add_integer_array(dp, "speeds", speed,
251 ARRAY_SIZE(speed)));
252
253 ptr = acpigen_get_current(ctx);
254 ut_assertok(acpi_dp_write(ctx, dp));
255 ut_asserteq(75, acpigen_get_current(ctx) - ptr);
256
257 ut_asserteq(BYTE_PREFIX, ptr[0x38]);
258 ut_asserteq(TEST_INT8, ptr[0x39]);
259
260 ut_asserteq(WORD_PREFIX, ptr[0x3a]);
261 ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x3b)));
262
263 ut_asserteq(DWORD_PREFIX, ptr[0x3d]);
264 ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 0x3e)));
265
266 ut_asserteq(QWORD_PREFIX, ptr[0x42]);
267 ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 0x43)));
268
269 free_context(&ctx);
270
271 return 0;
272}
273DM_TEST(dm_test_acpi_dp_array, 0);
274
275/* Test emitting a child */
276static int dm_test_acpi_dp_child(struct unit_test_state *uts)
277{
278 struct acpi_ctx *ctx;
279 struct acpi_dp *dp, *child1, *child2;
280 char uuid[UUID_STR_LEN + 1];
281 u8 *ptr, *pptr;
282 int i;
283
284 ut_assertok(alloc_context(&ctx));
285
286 child1 = acpi_dp_new_table("child");
287 ut_assertnonnull(child1);
288 ut_assertnonnull(acpi_dp_add_integer(child1, "height", TEST_INT16));
289
290 child2 = acpi_dp_new_table("child");
291 ut_assertnonnull(child2);
292 ut_assertnonnull(acpi_dp_add_integer(child2, "age", TEST_INT8));
293
294 dp = acpi_dp_new_table("FRED");
295 ut_assertnonnull(dp);
296
297 ut_assertnonnull(acpi_dp_add_child(dp, "anna", child1));
298 ut_assertnonnull(acpi_dp_add_child(dp, "john", child2));
299
300 ptr = acpigen_get_current(ctx);
301 ut_assertok(acpi_dp_write(ctx, dp));
302 ut_asserteq(178, acpigen_get_current(ctx) - ptr);
303
304 /* UUID for child extension using Hierarchical Data Extension UUID */
305 ut_asserteq(BUFFER_OP, ptr[10]);
306 ut_asserteq(22, acpi_test_get_length(ptr + 11));
307 ut_asserteq(WORD_PREFIX, ptr[14]);
308 ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
309 uuid_bin_to_str(ptr + 17, uuid, 1);
310 ut_asserteq_str(ACPI_DP_CHILD_UUID, uuid);
311
312 /* Package with two children */
313 ut_asserteq(PACKAGE_OP, ptr[0x21]);
314 ut_asserteq(0x28, acpi_test_get_length(ptr + 0x22));
315 ut_asserteq(2, ptr[0x25]);
316
317 /* First we expect the two children as string/value */
318 pptr = ptr + 0x26;
319 for (i = 0; i < 2; i++) {
320 ut_asserteq(PACKAGE_OP, pptr[0]);
321 ut_asserteq(0x11, acpi_test_get_length(pptr + 1));
322 ut_asserteq(2, pptr[4]);
323 ut_asserteq(STRING_PREFIX, pptr[5]);
324 ut_asserteq_str(i ? "john" : "anna", (char *)pptr + 6);
325 ut_asserteq(STRING_PREFIX, pptr[11]);
326 ut_asserteq_str("child", (char *)pptr + 12);
327 pptr += 0x12;
328 }
329
330 /* Write the two children */
331 ut_asserteq(0x4a, pptr - ptr);
332 for (i = 0; i < 2; i++) {
333 const char *prop = i ? "age" : "height";
334 const int datalen = i ? 1 : 2;
335 int len = strlen(prop) + 1;
336
337 ut_asserteq(NAME_OP, pptr[0]);
338 ut_asserteq_strn("chil", (char *)pptr + 1);
339 ut_asserteq(PACKAGE_OP, pptr[5]);
340 ut_asserteq(0x27 + len + datalen, acpi_test_get_length(pptr + 6));
341 ut_asserteq(2, pptr[9]);
342
343 /* UUID */
344 ut_asserteq(BUFFER_OP, pptr[10]);
345 ut_asserteq(22, acpi_test_get_length(pptr + 11));
346 ut_asserteq(WORD_PREFIX, pptr[14]);
347 ut_asserteq(16, get_unaligned((u16 *)(pptr + 15)));
348 uuid_bin_to_str(pptr + 17, uuid, 1);
349 ut_asserteq_str(ACPI_DP_UUID, uuid);
350 pptr += 33;
351
352 /* Containing package */
353 ut_asserteq(i ? 0xa1 : 0x6b, pptr - ptr);
354 ut_asserteq(PACKAGE_OP, pptr[0]);
355 ut_asserteq(0xb + len + datalen, acpi_test_get_length(pptr + 1));
356 ut_asserteq(1, pptr[4]);
357
358 /* Package containing the property-name string and the value */
359 pptr += 5;
360 ut_asserteq(i ? 0xa6 : 0x70, pptr - ptr);
361 ut_asserteq(PACKAGE_OP, pptr[0]);
362 ut_asserteq(6 + len + datalen, acpi_test_get_length(pptr + 1));
363 ut_asserteq(2, pptr[4]);
364
365 ut_asserteq(STRING_PREFIX, pptr[5]);
366 ut_asserteq_str(i ? "age" : "height", (char *)pptr + 6);
367 pptr += 6 + len;
368 if (i) {
369 ut_asserteq(BYTE_PREFIX, pptr[0]);
370 ut_asserteq(TEST_INT8, pptr[1]);
371 } else {
372 ut_asserteq(WORD_PREFIX, pptr[0]);
373 ut_asserteq(TEST_INT16,
374 get_unaligned((u16 *)(pptr + 1)));
375 }
376 pptr += 1 + datalen;
377 }
378 ut_asserteq(178, pptr - ptr);
379
380 free_context(&ctx);
381
382 return 0;
383}
384DM_TEST(dm_test_acpi_dp_child, 0);
Simon Glass59534492020-07-07 13:11:57 -0600385
386/* Test emitting a GPIO */
387static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
388{
389 struct acpi_ctx *ctx;
390 struct acpi_dp *dp;
391 u8 *ptr, *pptr;
392
393 ut_assertok(alloc_context(&ctx));
394
395 dp = acpi_dp_new_table("FRED");
396 ut_assertnonnull(dp);
397
398 /* Try a few different parameters */
399 ut_assertnonnull(acpi_dp_add_gpio(dp, "reset", TEST_REF, 0x23, 0x24,
Simon Glass2f3c6ba2020-09-22 12:44:59 -0600400 ACPI_GPIO_ACTIVE_HIGH));
Simon Glass59534492020-07-07 13:11:57 -0600401 ut_assertnonnull(acpi_dp_add_gpio(dp, "allow", TEST_REF, 0, 0,
Simon Glass2f3c6ba2020-09-22 12:44:59 -0600402 ACPI_GPIO_ACTIVE_LOW));
Simon Glass59534492020-07-07 13:11:57 -0600403
404 ptr = acpigen_get_current(ctx);
405 ut_assertok(acpi_dp_write(ctx, dp));
406 ut_asserteq(0x6e, acpigen_get_current(ctx) - ptr);
407
408 pptr = ptr + 0x2c; //0x3a;
409 ut_asserteq_str("reset", (char *)pptr);
410 ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
411 ut_asserteq(0x23, pptr[0x1b]);
412 ut_asserteq(0x24, pptr[0x1d]);
413 ut_asserteq(ZERO_OP, pptr[0x1e]);
414
415 pptr = ptr + 0x51;
416 ut_asserteq_str("allow", (char *)pptr);
417 ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
418 ut_asserteq(ZERO_OP, pptr[0x1a]);
419 ut_asserteq(ZERO_OP, pptr[0x1b]);
420 ut_asserteq(ONE_OP, pptr[0x1c]);
421
422 return 0;
423}
424DM_TEST(dm_test_acpi_dp_gpio, 0);
Simon Glassdd0ed902020-07-07 13:11:58 -0600425
426/* Test copying info from the device tree to ACPI tables */
427static int dm_test_acpi_dp_copy(struct unit_test_state *uts)
428{
429 struct acpi_ctx *ctx;
430 struct udevice *dev;
431 struct acpi_dp *dp;
432 ofnode node;
433 u8 *ptr;
434
435 ut_assertok(alloc_context(&ctx));
436
437 dp = acpi_dp_new_table("FRED");
438 ut_assertnonnull(dp);
439
440 ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
441 ut_asserteq_str("a-test", dev->name);
442
443 ut_assertok(acpi_dp_dev_copy_int(dev, dp, "int-value"));
444 ut_asserteq(-EINVAL, acpi_dp_dev_copy_int(dev, dp, "missing-value"));
445 ut_assertok(acpi_dp_dev_copy_int(dev, dp, "uint-value"));
446
447 ut_assertok(acpi_dp_dev_copy_str(dev, dp, "str-value"));
448 ut_asserteq(-EINVAL, acpi_dp_dev_copy_str(dev, dp, "missing-value"));
449
450 node = ofnode_path("/chosen");
451 ut_assert(ofnode_valid(node));
452 ut_assertok(acpi_dp_ofnode_copy_int(node, dp, "int-values"));
453 ut_asserteq(-EINVAL,
454 acpi_dp_ofnode_copy_int(node, dp, "missing-value"));
455
456 ut_assertok(acpi_dp_ofnode_copy_str(node, dp, "setting"));
457 ut_asserteq(-EINVAL,
458 acpi_dp_ofnode_copy_str(node, dp, "missing-value"));
459
460 ptr = acpigen_get_current(ctx);
461 ut_assertok(acpi_dp_write(ctx, dp));
462 ut_asserteq(0x9d, acpigen_get_current(ctx) - ptr);
463
464 ut_asserteq(STRING_PREFIX, ptr[0x2b]);
465 ut_asserteq_str("int-value", (char *)ptr + 0x2c);
466 ut_asserteq(WORD_PREFIX, ptr[0x36]);
467 ut_asserteq(1234, get_unaligned((u16 *)(ptr + 0x37)));
468
469 ut_asserteq(STRING_PREFIX, ptr[0x3e]);
470 ut_asserteq_str("uint-value", (char *)ptr + 0x3f);
471 ut_asserteq(DWORD_PREFIX, ptr[0x4a]);
472 ut_asserteq(-1234, get_unaligned((u32 *)(ptr + 0x4b)));
473
474 ut_asserteq(STRING_PREFIX, ptr[0x54]);
475 ut_asserteq_str("str-value", (char *)ptr + 0x55);
476 ut_asserteq(STRING_PREFIX, ptr[0x5f]);
477 ut_asserteq_str("test string", (char *)ptr + 0x60);
478
479 ut_asserteq(STRING_PREFIX, ptr[0x71]);
480 ut_asserteq_str("int-values", (char *)ptr + 0x72);
481 ut_asserteq(WORD_PREFIX, ptr[0x7d]);
482 ut_asserteq(0x1937, get_unaligned((u16 *)(ptr + 0x7e)));
483
484 ut_asserteq(STRING_PREFIX, ptr[0x85]);
485 ut_asserteq_str("setting", (char *)ptr + 0x86);
486 ut_asserteq(STRING_PREFIX, ptr[0x8e]);
487 ut_asserteq_str("sunrise ohoka", (char *)(ptr + 0x8f));
488
489 return 0;
490}
Simon Glass1a92f832024-08-22 07:57:48 -0600491DM_TEST(dm_test_acpi_dp_copy, UTF_SCAN_PDATA | UTF_SCAN_FDT);