summaryrefslogtreecommitdiff
path: root/lib/acpi
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2020-09-22 21:44:58 +0300
committerBin Meng <bmeng.cn@gmail.com>2020-09-25 06:27:14 +0300
commit88490e197903f6961cf2ee79d0ff8f0727155f27 (patch)
tree85ba227fc1fc17f47666a92c20c9844f40b0ce85 /lib/acpi
parentda7cff338f08cf43706a96bcd8cf398b7fb6ae2d (diff)
downloadu-boot-88490e197903f6961cf2ee79d0ff8f0727155f27.tar.xz
acpi: Support generating a multi-function _DSM for devices
Add a function to generate ACPI code for a _DSM method for a device. This includes functions for starting and ending each part of the _DSM. Signed-off-by: Simon Glass <sjg@chromium.org> [bmeng: fix the "new blank line at EOF" git warning] Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'lib/acpi')
-rw-r--r--lib/acpi/acpi_device.c43
-rw-r--r--lib/acpi/acpigen.c54
2 files changed, 97 insertions, 0 deletions
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c
index 3c75b6d962..8248664a10 100644
--- a/lib/acpi/acpi_device.c
+++ b/lib/acpi/acpi_device.c
@@ -487,6 +487,49 @@ int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val,
return 0;
}
+int acpi_device_write_dsm_i2c_hid(struct acpi_ctx *ctx,
+ int hid_desc_reg_offset)
+{
+ int ret;
+
+ acpigen_write_dsm_start(ctx);
+ ret = acpigen_write_dsm_uuid_start(ctx, ACPI_DSM_I2C_HID_UUID);
+ if (ret)
+ return log_ret(ret);
+
+ acpigen_write_dsm_uuid_start_cond(ctx, 0);
+ /* ToInteger (Arg1, Local2) */
+ acpigen_write_to_integer(ctx, ARG1_OP, LOCAL2_OP);
+ /* If (LEqual (Local2, 0x0)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x0);
+ /* Return (Buffer (One) { 0x1f }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x1f);
+ acpigen_pop_len(ctx); /* Pop : If */
+ /* Else */
+ acpigen_write_else(ctx);
+ /* If (LEqual (Local2, 0x1)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL2_OP, 0x1);
+ /* Return (Buffer (One) { 0x3f }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x3f);
+ acpigen_pop_len(ctx); /* Pop : If */
+ /* Else */
+ acpigen_write_else(ctx);
+ /* Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+ acpigen_pop_len(ctx); /* Pop : Else */
+ acpigen_pop_len(ctx); /* Pop : Else */
+ acpigen_write_dsm_uuid_end_cond(ctx);
+
+ acpigen_write_dsm_uuid_start_cond(ctx, 1);
+ acpigen_write_return_byte(ctx, hid_desc_reg_offset);
+ acpigen_write_dsm_uuid_end_cond(ctx);
+
+ acpigen_write_dsm_uuid_end(ctx);
+ acpigen_write_dsm_end(ctx);
+
+ return 0;
+}
+
/* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */
static void acpi_device_write_i2c(struct acpi_ctx *ctx,
const struct acpi_i2c *i2c)
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 2518bf83dd..d859f37841 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -609,6 +609,60 @@ void acpigen_write_return_byte(struct acpi_ctx *ctx, uint arg)
acpigen_write_byte(ctx, arg);
}
+void acpigen_write_dsm_start(struct acpi_ctx *ctx)
+{
+ /* Method (_DSM, 4, Serialized) */
+ acpigen_write_method_serialized(ctx, "_DSM", 4);
+
+ /* ToBuffer (Arg0, Local0) */
+ acpigen_write_to_buffer(ctx, ARG0_OP, LOCAL0_OP);
+}
+
+int acpigen_write_dsm_uuid_start(struct acpi_ctx *ctx, const char *uuid)
+{
+ int ret;
+
+ /* If (LEqual (Local0, ToUUID(uuid))) */
+ acpigen_write_if(ctx);
+ acpigen_emit_byte(ctx, LEQUAL_OP);
+ acpigen_emit_byte(ctx, LOCAL0_OP);
+ ret = acpigen_write_uuid(ctx, uuid);
+ if (ret)
+ return log_msg_ret("uuid", ret);
+
+ /* ToInteger (Arg2, Local1) */
+ acpigen_write_to_integer(ctx, ARG2_OP, LOCAL1_OP);
+
+ return 0;
+}
+
+void acpigen_write_dsm_uuid_start_cond(struct acpi_ctx *ctx, int seq)
+{
+ /* If (LEqual (Local1, i)) */
+ acpigen_write_if_lequal_op_int(ctx, LOCAL1_OP, seq);
+}
+
+void acpigen_write_dsm_uuid_end_cond(struct acpi_ctx *ctx)
+{
+ acpigen_pop_len(ctx); /* If */
+}
+
+void acpigen_write_dsm_uuid_end(struct acpi_ctx *ctx)
+{
+ /* Default case: Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+ acpigen_pop_len(ctx); /* If (LEqual (Local0, ToUUID(uuid))) */
+}
+
+void acpigen_write_dsm_end(struct acpi_ctx *ctx)
+{
+ /* Return (Buffer (One) { 0x0 }) */
+ acpigen_write_return_singleton_buffer(ctx, 0x0);
+
+ acpigen_pop_len(ctx); /* Method _DSM */
+}
+
/**
* acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5
*