diff options
Diffstat (limited to 'src/soc/amd/stoneyridge/acpi.c')
-rw-r--r-- | src/soc/amd/stoneyridge/acpi.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/soc/amd/stoneyridge/acpi.c b/src/soc/amd/stoneyridge/acpi.c index d7aa088fb0..8130b79c2c 100644 --- a/src/soc/amd/stoneyridge/acpi.c +++ b/src/soc/amd/stoneyridge/acpi.c @@ -32,6 +32,7 @@ #include <soc/pci_devs.h> #include <soc/southbridge.h> #include <soc/nvs.h> +#include <soc/gpio.h> unsigned long acpi_fill_madt(unsigned long current) { @@ -303,3 +304,100 @@ void southbridge_inject_dsdt(struct device *device) acpigen_pop_len(); } } + +static void acpigen_soc_get_gpio_in_local5(uintptr_t addr) +{ + /* + * Store (\_SB.GPR2 (addr), Local5) + * \_SB.GPR2 is used to read control byte 2 from control register. + * / It is defined in gpio_lib.asl. + */ + acpigen_write_store(); + acpigen_emit_namestring("\\_SB.GPR2"); + acpigen_write_integer(addr); + acpigen_emit_byte(LOCAL5_OP); +} + +static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask) +{ + if (gpio_num >= GPIO_TOTAL_PINS) { + printk(BIOS_WARNING, "Warning: Pin %d should be smaller than" + " %d\n", gpio_num, GPIO_TOTAL_PINS); + return -1; + } + uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num); + + acpigen_soc_get_gpio_in_local5(addr); + + /* If (And (Local5, mask)) */ + acpigen_write_if_and(LOCAL5_OP, mask); + + /* Store (One, Local0) */ + acpigen_write_store_ops(ONE_OP, LOCAL0_OP); + + acpigen_pop_len(); /* If */ + + /* Else */ + acpigen_write_else(); + + /* Store (Zero, Local0) */ + acpigen_write_store_ops(ZERO_OP, LOCAL0_OP); + + acpigen_pop_len(); /* Else */ + + return 0; +} + +static int acpigen_soc_set_gpio_val(unsigned int gpio_num, uint32_t val) +{ + if (gpio_num >= GPIO_TOTAL_PINS) { + printk(BIOS_WARNING, "Warning: Pin %d should be smaller than" + " %d\n", gpio_num, GPIO_TOTAL_PINS); + return -1; + } + uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num); + + acpigen_soc_get_gpio_in_local5(addr); + + if (val) { + /* Or (Local5, GPIO_PIN_OUT, Local5) */ + acpigen_write_or(LOCAL5_OP, GPIO_PIN_OUT, LOCAL5_OP); + } else { + /* Not (GPIO_PIN_OUT, Local6) */ + acpigen_write_not(GPIO_PIN_OUT, LOCAL6_OP); + + /* And (Local5, Local6, Local5) */ + acpigen_write_and(LOCAL5_OP, LOCAL6_OP, LOCAL5_OP); + } + + /* + * SB.GPW2 (addr, Local5) + * \_SB.GPW2 is used to write control byte in control register + * / byte 2. It is defined in gpio_lib.asl. + */ + acpigen_emit_namestring("\\_SB.GPW2"); + acpigen_write_integer(addr); + acpigen_emit_byte(LOCAL5_OP); + + return 0; +} + +int acpigen_soc_read_rx_gpio(unsigned int gpio_num) +{ + return acpigen_soc_get_gpio_val(gpio_num, GPIO_PIN_IN); +} + +int acpigen_soc_get_tx_gpio(unsigned int gpio_num) +{ + return acpigen_soc_get_gpio_val(gpio_num, GPIO_PIN_OUT); +} + +int acpigen_soc_set_tx_gpio(unsigned int gpio_num) +{ + return acpigen_soc_set_gpio_val(gpio_num, 1); +} + +int acpigen_soc_clear_tx_gpio(unsigned int gpio_num) +{ + return acpigen_soc_set_gpio_val(gpio_num, 0); +} |