diff options
-rw-r--r-- | src/soc/amd/stoneyridge/acpi.c | 98 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/gpio.c | 2 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/gpio.h | 6 |
3 files changed, 105 insertions, 1 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); +} diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c index 3bb77b7010..65134762a8 100644 --- a/src/soc/amd/stoneyridge/gpio.c +++ b/src/soc/amd/stoneyridge/gpio.c @@ -130,7 +130,7 @@ static void get_sci_config_bits(uint32_t flag, uint32_t *edge, uint32_t *level) } } -static uintptr_t gpio_get_address(gpio_t gpio_num) +uintptr_t gpio_get_address(gpio_t gpio_num) { uintptr_t gpio_address; diff --git a/src/soc/amd/stoneyridge/include/soc/gpio.h b/src/soc/amd/stoneyridge/include/soc/gpio.h index 6133bf1684..6e722933b8 100644 --- a/src/soc/amd/stoneyridge/include/soc/gpio.h +++ b/src/soc/amd/stoneyridge/include/soc/gpio.h @@ -36,6 +36,10 @@ struct soc_amd_event { uint8_t event; }; +#define GPIO_TOTAL_PINS 149 +#define GPIO_PIN_IN (1 << 0) /* for byte access */ +#define GPIO_PIN_OUT (1 << 6) /* for byte access */ + #define GPIO_EDGE_TRIG (0 << 8) #define GPIO_LEVEL_TRIG (1 << 8) #define GPIO_TRIGGER_MASK (1 << 8) @@ -555,6 +559,8 @@ enum { .flags = GPIO_FLAG_DEBOUNCE } typedef uint32_t gpio_t; +/* Get the address of the control register of a particular pin */ +uintptr_t gpio_get_address(gpio_t gpio_num); /** * @brief program a particular set of GPIO |