diff options
author | Simon Glass <sjg@chromium.org> | 2020-07-08 06:32:11 +0300 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2020-07-17 09:32:24 +0300 |
commit | d7d631df2d4f32710dbecb020e375b9c0d986225 (patch) | |
tree | 73a434686ab35f6baa4643a29f6a6a0035ef395f /lib/acpi | |
parent | 82659cc91014df7dfcc55474c1657d1c9b6fe957 (diff) | |
download | u-boot-d7d631df2d4f32710dbecb020e375b9c0d986225.tar.xz |
acpi: Support generation of a generic register
Allow writing out a generic register.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
[bmeng: Fix build failures on Sandbox]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'lib/acpi')
-rw-r--r-- | lib/acpi/acpigen.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c index 1e0a489d7b..45691b7961 100644 --- a/lib/acpi/acpigen.c +++ b/lib/acpi/acpigen.c @@ -14,6 +14,7 @@ #include <uuid.h> #include <acpi/acpigen.h> #include <acpi/acpi_device.h> +#include <acpi/acpi_table.h> #include <dm/acpi.h> u8 *acpigen_get_current(struct acpi_ctx *ctx) @@ -299,6 +300,76 @@ void acpigen_write_sta(struct acpi_ctx *ctx, uint status) acpigen_pop_len(ctx); } +static void acpigen_write_register(struct acpi_ctx *ctx, + const struct acpi_gen_regaddr *addr) +{ + /* See ACPI v6.3 section 6.4.3.7: Generic Register Descriptor */ + acpigen_emit_byte(ctx, ACPI_DESCRIPTOR_REGISTER); + acpigen_emit_byte(ctx, 0x0c); /* Register Length 7:0 */ + acpigen_emit_byte(ctx, 0x00); /* Register Length 15:8 */ + acpigen_emit_byte(ctx, addr->space_id); + acpigen_emit_byte(ctx, addr->bit_width); + acpigen_emit_byte(ctx, addr->bit_offset); + acpigen_emit_byte(ctx, addr->access_size); + acpigen_emit_dword(ctx, addr->addrl); + acpigen_emit_dword(ctx, addr->addrh); +} + +void acpigen_write_resourcetemplate_header(struct acpi_ctx *ctx) +{ + /* + * A ResourceTemplate() is a Buffer() with a + * (Byte|Word|DWord) containing the length, followed by one or more + * resource items, terminated by the end tag. + * (small item 0xf, len 1) + */ + acpigen_emit_byte(ctx, BUFFER_OP); + acpigen_write_len_f(ctx); + acpigen_emit_byte(ctx, WORD_PREFIX); + ctx->len_stack[ctx->ltop++] = ctx->current; + + /* + * Add two dummy bytes for the ACPI word (keep aligned with the + * calculation in acpigen_write_resourcetemplate_footer() below) + */ + acpigen_emit_byte(ctx, 0x00); + acpigen_emit_byte(ctx, 0x00); +} + +void acpigen_write_resourcetemplate_footer(struct acpi_ctx *ctx) +{ + char *p = ctx->len_stack[--ctx->ltop]; + int len; + /* + * See ACPI v6.3 section 6.4.2.9: End Tag + * 0x79 <checksum> + * 0x00 is treated as a good checksum according to the spec + * and is what iasl generates. + */ + acpigen_emit_byte(ctx, ACPI_END_TAG); + acpigen_emit_byte(ctx, 0x00); + + /* + * Start counting past the 2-bytes length added in + * acpigen_write_resourcetemplate_header() above + */ + len = (char *)ctx->current - (p + 2); + + /* patch len word */ + p[0] = len & 0xff; + p[1] = (len >> 8) & 0xff; + + acpigen_pop_len(ctx); +} + +void acpigen_write_register_resource(struct acpi_ctx *ctx, + const struct acpi_gen_regaddr *addr) +{ + acpigen_write_resourcetemplate_header(ctx); + acpigen_write_register(ctx, addr); + acpigen_write_resourcetemplate_footer(ctx); +} + /* * ToUUID(uuid) * |