aboutsummaryrefslogtreecommitdiff
path: root/lib/acpi
diff options
context:
space:
mode:
authorSimon Glass2020-07-07 13:12:01 -0600
committerBin Meng2020-07-17 14:32:24 +0800
commitf8054dd8ba533be0e2ebd7965b95446a1f573953 (patch)
tree3236d3b0505cb448f60289636a53643ee538a3a3 /lib/acpi
parentf9189d5ada8d48932463dc1d56ea4d44c050ebbd (diff)
acpi: Add support for writing a GPIO power sequence
Power to some devices is controlled by GPIOs. Add a way to generate ACPI code to enable and disable a GPIO so that this can be handled within an ACPI method. 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 'lib/acpi')
-rw-r--r--lib/acpi/acpigen.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c
index 70d734245bb..45216c1f9d6 100644
--- a/lib/acpi/acpigen.c
+++ b/lib/acpi/acpigen.c
@@ -13,6 +13,7 @@
#include <log.h>
#include <uuid.h>
#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
#include <dm/acpi.h>
u8 *acpigen_get_current(struct acpi_ctx *ctx)
@@ -395,3 +396,87 @@ void acpigen_write_debug_string(struct acpi_ctx *ctx, const char *str)
acpigen_write_string(ctx, str);
acpigen_emit_ext_op(ctx, DEBUG_OP);
}
+
+/**
+ * acpigen_get_dw0_in_local5() - Generate code to put dw0 cfg0 in local5
+ *
+ * Store (\_SB.GPC0 (addr), Local5)
+ *
+ * \_SB.GPC0 is used to read cfg0 value from dw0. It is typically defined in
+ * the board's gpiolib.asl
+ *
+ * The value needs to be stored in a local variable so that it can be used in
+ * expressions in the ACPI code.
+ *
+ * @ctx: ACPI context pointer
+ * @dw0_read: Name to use to read dw0, e.g. "\\_SB.GPC0"
+ * @addr: GPIO pin configuration register address
+ *
+ */
+static void acpigen_get_dw0_in_local5(struct acpi_ctx *ctx,
+ const char *dw0_read, ulong addr)
+{
+ acpigen_write_store(ctx);
+ acpigen_emit_namestring(ctx, dw0_read);
+ acpigen_write_integer(ctx, addr);
+ acpigen_emit_byte(ctx, LOCAL5_OP);
+}
+
+/**
+ * acpigen_set_gpio_val() - Emit code to set value of TX GPIO to on/off
+ *
+ * @ctx: ACPI context pointer
+ * @dw0_read: Method name to use to read dw0, e.g. "\\_SB.GPC0"
+ * @dw0_write: Method name to use to read dw0, e.g. "\\_SB.SPC0"
+ * @gpio_num: GPIO number to adjust
+ * @vaL: true to set on, false to set off
+ */
+static int acpigen_set_gpio_val(struct acpi_ctx *ctx, u32 tx_state_val,
+ const char *dw0_read, const char *dw0_write,
+ struct acpi_gpio *gpio, bool val)
+{
+ acpigen_get_dw0_in_local5(ctx, dw0_read, gpio->pin0_addr);
+
+ /* Store (0x40, Local0) */
+ acpigen_write_store(ctx);
+ acpigen_write_integer(ctx, tx_state_val);
+ acpigen_emit_byte(ctx, LOCAL0_OP);
+
+ if (val) {
+ /* Or (Local5, PAD_CFG0_TX_STATE, Local5) */
+ acpigen_write_or(ctx, LOCAL5_OP, LOCAL0_OP, LOCAL5_OP);
+ } else {
+ /* Not (PAD_CFG0_TX_STATE, Local6) */
+ acpigen_write_not(ctx, LOCAL0_OP, LOCAL6_OP);
+
+ /* And (Local5, Local6, Local5) */
+ acpigen_write_and(ctx, LOCAL5_OP, LOCAL6_OP, LOCAL5_OP);
+ }
+
+ /*
+ * \_SB.SPC0 (addr, Local5)
+ * \_SB.SPC0 is used to write cfg0 value in dw0. It is defined in
+ * gpiolib.asl.
+ */
+ acpigen_emit_namestring(ctx, dw0_write);
+ acpigen_write_integer(ctx, gpio->pin0_addr);
+ acpigen_emit_byte(ctx, LOCAL5_OP);
+
+ return 0;
+}
+
+int acpigen_set_enable_tx_gpio(struct acpi_ctx *ctx, u32 tx_state_val,
+ const char *dw0_read, const char *dw0_write,
+ struct acpi_gpio *gpio, bool enable)
+{
+ bool set;
+ int ret;
+
+ set = gpio->polarity == ACPI_GPIO_ACTIVE_HIGH ? enable : !enable;
+ ret = acpigen_set_gpio_val(ctx, tx_state_val, dw0_read, dw0_write, gpio,
+ set);
+ if (ret)
+ return log_msg_ret("call", ret);
+
+ return 0;
+}