diff options
author | Simon Glass | 2020-07-07 13:12:01 -0600 |
---|---|---|
committer | Bin Meng | 2020-07-17 14:32:24 +0800 |
commit | f8054dd8ba533be0e2ebd7965b95446a1f573953 (patch) | |
tree | 3236d3b0505cb448f60289636a53643ee538a3a3 /lib/acpi | |
parent | f9189d5ada8d48932463dc1d56ea4d44c050ebbd (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.c | 85 |
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; +} |