mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-16 18:04:48 +00:00
acpi: Support generation of ACPI code
Add a new file to handle generating ACPI code programatically. This is used when information must be dynamically added to the tables, e.g. the SSDT. Initial support is just for writing simple values. Also add a 'base' value so that the table can be freed. This likely doesn't happen in normal code, but is nice to do in tests. 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>
This commit is contained in:
parent
f4955137f5
commit
61cc93396a
7 changed files with 165 additions and 0 deletions
49
include/acpi/acpigen.h
Normal file
49
include/acpi/acpigen.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* 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
|
|
@ -29,6 +29,7 @@
|
|||
*
|
||||
* 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.
|
||||
|
@ -36,6 +37,7 @@
|
|||
* @xsdt: Pointer to the Extended System Description Table
|
||||
*/
|
||||
struct acpi_ctx {
|
||||
void *base;
|
||||
void *current;
|
||||
struct acpi_rsdp *rsdp;
|
||||
struct acpi_rsdt *rsdt;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
|
||||
obj-y += acpigen.o
|
||||
obj-y += acpi_device.o
|
||||
obj-y += acpi_table.o
|
||||
|
|
|
@ -237,6 +237,7 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt)
|
|||
|
||||
void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start)
|
||||
{
|
||||
ctx->base = start;
|
||||
ctx->current = start;
|
||||
|
||||
/* Align ACPI tables to 16 byte */
|
||||
|
|
39
lib/acpi/acpigen.c
Normal file
39
lib/acpi/acpigen.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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);
|
||||
}
|
|
@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
|
|||
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
|
||||
|
|
72
test/dm/acpigen.c
Normal file
72
test/dm/acpigen.c
Normal file
|
@ -0,0 +1,72 @@
|
|||
// 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);
|
Loading…
Add table
Reference in a new issue