diff options
author | Simon Glass <sjg@chromium.org> | 2020-07-07 13:11:56 -0600 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2020-07-17 14:32:24 +0800 |
commit | 0e5a0a00d6e44dc0c7e1466ceb3e452b43ceeb1b (patch) | |
tree | df19c9ee9a3d00dc9acb646541dcd7ad7d250287 /test/dm/acpi_dp.c | |
parent | 29df845204e6b67583491b3c9883432c3a74d923 (diff) | |
download | u-boot-0e5a0a00d6e44dc0c7e1466ceb3e452b43ceeb1b.tar.gz u-boot-0e5a0a00d6e44dc0c7e1466ceb3e452b43ceeb1b.tar.bz2 u-boot-0e5a0a00d6e44dc0c7e1466ceb3e452b43ceeb1b.zip |
acpi: Support writing Device Properties objects via _DSD
More complex device properties can be provided to drivers via a
device-specific data (_DSD) object.
To create this we need to build it up in a separate data structure and
then generate the ACPI code, due to its recursive nature.
Add an implementation of this.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'test/dm/acpi_dp.c')
-rw-r--r-- | test/dm/acpi_dp.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/test/dm/acpi_dp.c b/test/dm/acpi_dp.c new file mode 100644 index 0000000000..28696aaff6 --- /dev/null +++ b/test/dm/acpi_dp.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for ACPI code generation via a device-property table + * + * Copyright 2019 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <uuid.h> +#include <acpi/acpigen.h> +#include <acpi/acpi_dp.h> +#include <asm/unaligned.h> +#include <dm/acpi.h> +#include <dm/test.h> +#include <test/ut.h> +#include "acpi.h" + +/* Maximum size of the ACPI context needed for most tests */ +#define ACPI_CONTEXT_SIZE 500 + +#define TEST_INT8 0x7d +#define TEST_INT16 0x2345 +#define TEST_INT32 0x12345678 +#define TEST_INT64 0x4567890123456 +#define TEST_STR "testing acpi strings" +#define TEST_REF "\\SB.I2C0.TPM2" +#define EXPECT_REF "SB__I2C0TPM2" + +static int alloc_context(struct acpi_ctx **ctxp) +{ + return acpi_test_alloc_context_size(ctxp, ACPI_CONTEXT_SIZE); + + return 0; +} + +static void free_context(struct acpi_ctx **ctxp) +{ + free(*ctxp); + *ctxp = NULL; +} + +/* Test emitting an empty table */ +static int dm_test_acpi_dp_new_table(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(10, acpigen_get_current(ctx) - ptr); + ut_asserteq(NAME_OP, *(u8 *)ptr); + ut_asserteq_strn("FRED", (char *)ptr + 1); + ut_asserteq(PACKAGE_OP, ptr[5]); + ut_asserteq(4, acpi_test_get_length(ptr + 6)); + ut_asserteq(0, ptr[9]); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_new_table, 0); + +/* Test emitting an integer */ +static int dm_test_acpi_dp_int(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + char uuid[UUID_STR_LEN + 1]; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT32)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(54, acpigen_get_current(ctx) - ptr); + ut_asserteq(NAME_OP, *(u8 *)ptr); + ut_asserteq_strn("FRED", (char *)ptr + 1); + ut_asserteq(PACKAGE_OP, ptr[5]); + ut_asserteq(48, acpi_test_get_length(ptr + 6)); + ut_asserteq(2, ptr[9]); + + /* UUID */ + ut_asserteq(BUFFER_OP, ptr[10]); + ut_asserteq(22, acpi_test_get_length(ptr + 11)); + ut_asserteq(WORD_PREFIX, ptr[14]); + ut_asserteq(16, get_unaligned((u16 *)(ptr + 15))); + uuid_bin_to_str(ptr + 17, uuid, 1); + ut_asserteq_str(ACPI_DP_UUID, uuid); + + /* Container package */ + ut_asserteq(PACKAGE_OP, ptr[33]); + ut_asserteq(20, acpi_test_get_length(ptr + 34)); + ut_asserteq(1, ptr[37]); + + /* Package with name and (integer) value */ + ut_asserteq(PACKAGE_OP, ptr[38]); + ut_asserteq(15, acpi_test_get_length(ptr + 39)); + ut_asserteq(2, ptr[42]); + ut_asserteq(STRING_PREFIX, ptr[43]); + ut_asserteq_str("MARY", (char *)ptr + 44); + + ut_asserteq(DWORD_PREFIX, ptr[49]); + ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 50))); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_int, 0); + +/* Test emitting a 64-bit integer */ +static int dm_test_acpi_dp_int64(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT64)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(58, acpigen_get_current(ctx) - ptr); + + ut_asserteq(QWORD_PREFIX, ptr[49]); + ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 50))); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_int64, 0); + +/* Test emitting a 16-bit integer */ +static int dm_test_acpi_dp_int16(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT16)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(52, acpigen_get_current(ctx) - ptr); + + ut_asserteq(WORD_PREFIX, ptr[49]); + ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 50))); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_int16, 0); + +/* Test emitting a 8-bit integer */ +static int dm_test_acpi_dp_int8(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT8)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(51, acpigen_get_current(ctx) - ptr); + + ut_asserteq(BYTE_PREFIX, ptr[49]); + ut_asserteq(TEST_INT8, ptr[50]); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_int8, 0); + +/* Test emitting multiple values */ +static int dm_test_acpi_dp_multiple(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + ut_assertnonnull(acpi_dp_add_integer(dp, "int16", TEST_INT16)); + ut_assertnonnull(acpi_dp_add_string(dp, "str", TEST_STR)); + ut_assertnonnull(acpi_dp_add_reference(dp, "ref", TEST_REF)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(110, acpigen_get_current(ctx) - ptr); + + ut_asserteq(WORD_PREFIX, ptr[0x32]); + ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x33))); + ut_asserteq(STRING_PREFIX, ptr[0x3f]); + ut_asserteq_str(TEST_STR, (char *)ptr + 0x40); + ut_asserteq(ROOT_PREFIX, ptr[0x5f]); + ut_asserteq(MULTI_NAME_PREFIX, ptr[0x60]); + ut_asserteq(3, ptr[0x61]); + ut_asserteq_strn(EXPECT_REF, (char *)ptr + 0x62); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_multiple, 0); + +/* Test emitting an array */ +static int dm_test_acpi_dp_array(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp; + u64 speed[4]; + u8 *ptr; + + ut_assertok(alloc_context(&ctx)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + speed[0] = TEST_INT8; + speed[1] = TEST_INT16; + speed[2] = TEST_INT32; + speed[3] = TEST_INT64; + ut_assertnonnull(acpi_dp_add_integer_array(dp, "speeds", speed, + ARRAY_SIZE(speed))); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(75, acpigen_get_current(ctx) - ptr); + + ut_asserteq(BYTE_PREFIX, ptr[0x38]); + ut_asserteq(TEST_INT8, ptr[0x39]); + + ut_asserteq(WORD_PREFIX, ptr[0x3a]); + ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x3b))); + + ut_asserteq(DWORD_PREFIX, ptr[0x3d]); + ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 0x3e))); + + ut_asserteq(QWORD_PREFIX, ptr[0x42]); + ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 0x43))); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_array, 0); + +/* Test emitting a child */ +static int dm_test_acpi_dp_child(struct unit_test_state *uts) +{ + struct acpi_ctx *ctx; + struct acpi_dp *dp, *child1, *child2; + char uuid[UUID_STR_LEN + 1]; + u8 *ptr, *pptr; + int i; + + ut_assertok(alloc_context(&ctx)); + + child1 = acpi_dp_new_table("child"); + ut_assertnonnull(child1); + ut_assertnonnull(acpi_dp_add_integer(child1, "height", TEST_INT16)); + + child2 = acpi_dp_new_table("child"); + ut_assertnonnull(child2); + ut_assertnonnull(acpi_dp_add_integer(child2, "age", TEST_INT8)); + + dp = acpi_dp_new_table("FRED"); + ut_assertnonnull(dp); + + ut_assertnonnull(acpi_dp_add_child(dp, "anna", child1)); + ut_assertnonnull(acpi_dp_add_child(dp, "john", child2)); + + ptr = acpigen_get_current(ctx); + ut_assertok(acpi_dp_write(ctx, dp)); + ut_asserteq(178, acpigen_get_current(ctx) - ptr); + + /* UUID for child extension using Hierarchical Data Extension UUID */ + ut_asserteq(BUFFER_OP, ptr[10]); + ut_asserteq(22, acpi_test_get_length(ptr + 11)); + ut_asserteq(WORD_PREFIX, ptr[14]); + ut_asserteq(16, get_unaligned((u16 *)(ptr + 15))); + uuid_bin_to_str(ptr + 17, uuid, 1); + ut_asserteq_str(ACPI_DP_CHILD_UUID, uuid); + + /* Package with two children */ + ut_asserteq(PACKAGE_OP, ptr[0x21]); + ut_asserteq(0x28, acpi_test_get_length(ptr + 0x22)); + ut_asserteq(2, ptr[0x25]); + + /* First we expect the two children as string/value */ + pptr = ptr + 0x26; + for (i = 0; i < 2; i++) { + ut_asserteq(PACKAGE_OP, pptr[0]); + ut_asserteq(0x11, acpi_test_get_length(pptr + 1)); + ut_asserteq(2, pptr[4]); + ut_asserteq(STRING_PREFIX, pptr[5]); + ut_asserteq_str(i ? "john" : "anna", (char *)pptr + 6); + ut_asserteq(STRING_PREFIX, pptr[11]); + ut_asserteq_str("child", (char *)pptr + 12); + pptr += 0x12; + } + + /* Write the two children */ + ut_asserteq(0x4a, pptr - ptr); + for (i = 0; i < 2; i++) { + const char *prop = i ? "age" : "height"; + const int datalen = i ? 1 : 2; + int len = strlen(prop) + 1; + + ut_asserteq(NAME_OP, pptr[0]); + ut_asserteq_strn("chil", (char *)pptr + 1); + ut_asserteq(PACKAGE_OP, pptr[5]); + ut_asserteq(0x27 + len + datalen, acpi_test_get_length(pptr + 6)); + ut_asserteq(2, pptr[9]); + + /* UUID */ + ut_asserteq(BUFFER_OP, pptr[10]); + ut_asserteq(22, acpi_test_get_length(pptr + 11)); + ut_asserteq(WORD_PREFIX, pptr[14]); + ut_asserteq(16, get_unaligned((u16 *)(pptr + 15))); + uuid_bin_to_str(pptr + 17, uuid, 1); + ut_asserteq_str(ACPI_DP_UUID, uuid); + pptr += 33; + + /* Containing package */ + ut_asserteq(i ? 0xa1 : 0x6b, pptr - ptr); + ut_asserteq(PACKAGE_OP, pptr[0]); + ut_asserteq(0xb + len + datalen, acpi_test_get_length(pptr + 1)); + ut_asserteq(1, pptr[4]); + + /* Package containing the property-name string and the value */ + pptr += 5; + ut_asserteq(i ? 0xa6 : 0x70, pptr - ptr); + ut_asserteq(PACKAGE_OP, pptr[0]); + ut_asserteq(6 + len + datalen, acpi_test_get_length(pptr + 1)); + ut_asserteq(2, pptr[4]); + + ut_asserteq(STRING_PREFIX, pptr[5]); + ut_asserteq_str(i ? "age" : "height", (char *)pptr + 6); + pptr += 6 + len; + if (i) { + ut_asserteq(BYTE_PREFIX, pptr[0]); + ut_asserteq(TEST_INT8, pptr[1]); + } else { + ut_asserteq(WORD_PREFIX, pptr[0]); + ut_asserteq(TEST_INT16, + get_unaligned((u16 *)(pptr + 1))); + } + pptr += 1 + datalen; + } + ut_asserteq(178, pptr - ptr); + + free_context(&ctx); + + return 0; +} +DM_TEST(dm_test_acpi_dp_child, 0); |