From f8054dd8ba533be0e2ebd7965b95446a1f573953 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 Jul 2020 13:12:01 -0600 Subject: 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 Reviewed-by: Wolfgang Wallner Reviewed-by: Bin Meng --- lib/acpi/acpigen.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'lib') diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c index 70d734245b..45216c1f9d 100644 --- a/lib/acpi/acpigen.c +++ b/lib/acpi/acpigen.c @@ -13,6 +13,7 @@ #include #include #include +#include #include 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; +} -- cgit v1.2.3