--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Core ACPI (Advanced Configuration and Power Interface) support
+ *
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot file acpigen.h
+ */
+
+#ifndef __ACPI_ACPIGEN_H
+#define __ACPI_ACPIGEN_H
+
+#include <linux/types.h>
+
+struct acpi_ctx;
+
+/**
+ * acpigen_get_current() - Get the current ACPI code output pointer
+ *
+ * @ctx: ACPI context pointer
+ * @return output pointer
+ */
+u8 *acpigen_get_current(struct acpi_ctx *ctx);
+
+/**
+ * acpigen_emit_byte() - Emit a byte to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_byte(struct acpi_ctx *ctx, uint data);
+
+/**
+ * acpigen_emit_word() - Emit a 16-bit word to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_word(struct acpi_ctx *ctx, uint data);
+
+/**
+ * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code
+ *
+ * @ctx: ACPI context pointer
+ * @data: Value to output
+ */
+void acpigen_emit_dword(struct acpi_ctx *ctx, uint data);
+
+#endif
*
* This contains a few useful pieces of information used when writing
*
+ * @base: Base address of ACPI tables
* @current: Current address for writing
* @rsdp: Pointer to the Root System Description Pointer, typically used when
* adding a new table. The RSDP holds pointers to the RSDT and XSDT.
* @xsdt: Pointer to the Extended System Description Table
*/
struct acpi_ctx {
+ void *base;
void *current;
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
# SPDX-License-Identifier: GPL-2.0+
#
+obj-y += acpigen.o
obj-y += acpi_device.o
obj-y += acpi_table.o
void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
{
+ ctx->base = start;
ctx->current = start;
/* Align ACPI tables to 16 byte */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generation of ACPI (Advanced Configuration and Power Interface) tables
+ *
+ * Copyright 2019 Google LLC
+ * Mostly taken from coreboot
+ */
+
+#define LOG_CATEGORY LOGC_ACPI
+
+#include <common.h>
+#include <dm.h>
+#include <acpi/acpigen.h>
+#include <dm/acpi.h>
+
+u8 *acpigen_get_current(struct acpi_ctx *ctx)
+{
+ return ctx->current;
+}
+
+void acpigen_emit_byte(struct acpi_ctx *ctx, uint data)
+{
+ *(u8 *)ctx->current++ = data;
+}
+
+void acpigen_emit_word(struct acpi_ctx *ctx, uint data)
+{
+ acpigen_emit_byte(ctx, data & 0xff);
+ acpigen_emit_byte(ctx, (data >> 8) & 0xff);
+}
+
+void acpigen_emit_dword(struct acpi_ctx *ctx, uint data)
+{
+ /* Output the value in little-endian format */
+ acpigen_emit_byte(ctx, data & 0xff);
+ acpigen_emit_byte(ctx, (data >> 8) & 0xff);
+ acpigen_emit_byte(ctx, (data >> 16) & 0xff);
+ acpigen_emit_byte(ctx, (data >> 24) & 0xff);
+}
obj-$(CONFIG_UT_DM) += core.o
ifneq ($(CONFIG_SANDBOX),)
obj-$(CONFIG_ACPIGEN) += acpi.o
+obj-$(CONFIG_ACPIGEN) += acpigen.o
obj-$(CONFIG_SOUND) += audio.o
obj-$(CONFIG_BLK) += blk.o
obj-$(CONFIG_BOARD) += board.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Tests for ACPI code generation
+ *
+ * Copyright 2019 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <acpi/acpigen.h>
+#include <asm/unaligned.h>
+#include <dm/acpi.h>
+#include <dm/test.h>
+#include <test/ut.h>
+
+/* Maximum size of the ACPI context needed for most tests */
+#define ACPI_CONTEXT_SIZE 150
+
+static int alloc_context(struct acpi_ctx **ctxp)
+{
+ struct acpi_ctx *ctx;
+
+ *ctxp = NULL;
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx)
+ return -ENOMEM;
+ ctx->base = malloc(ACPI_CONTEXT_SIZE);
+ if (!ctx->base) {
+ free(ctx);
+ return -ENOMEM;
+ }
+ ctx->current = ctx->base;
+ *ctxp = ctx;
+
+ return 0;
+}
+
+static void free_context(struct acpi_ctx **ctxp)
+{
+ free((*ctxp)->base);
+ free(*ctxp);
+ *ctxp = NULL;
+}
+
+/* Test emitting simple types and acpigen_get_current() */
+static int dm_test_acpi_emit_simple(struct unit_test_state *uts)
+{
+ struct acpi_ctx *ctx;
+ u8 *ptr;
+
+ ut_assertok(alloc_context(&ctx));
+
+ ptr = acpigen_get_current(ctx);
+ acpigen_emit_byte(ctx, 0x23);
+ ut_asserteq(1, acpigen_get_current(ctx) - ptr);
+ ut_asserteq(0x23, *(u8 *)ptr);
+
+ acpigen_emit_word(ctx, 0x1234);
+ ut_asserteq(3, acpigen_get_current(ctx) - ptr);
+ ut_asserteq(0x1234, get_unaligned((u16 *)(ptr + 1)));
+
+ acpigen_emit_dword(ctx, 0x87654321);
+ ut_asserteq(7, acpigen_get_current(ctx) - ptr);
+ ut_asserteq(0x87654321, get_unaligned((u32 *)(ptr + 3)));
+
+ free_context(&ctx);
+
+ return 0;
+}
+DM_TEST(dm_test_acpi_emit_simple, 0);