diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/common/block/gpio_banks/gpio.c | 71 | ||||
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/gpio_banks.h | 17 |
2 files changed, 88 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/gpio_banks/gpio.c b/src/soc/amd/common/block/gpio_banks/gpio.c index 4f1b842311..7fb6622f0a 100644 --- a/src/soc/amd/common/block/gpio_banks/gpio.c +++ b/src/soc/amd/common/block/gpio_banks/gpio.c @@ -3,12 +3,14 @@ #include <device/mmio.h> #include <device/device.h> #include <console/console.h> +#include <elog.h> #include <gpio.h> #include <amdblocks/acpimmio.h> #include <amdblocks/gpio_banks.h> #include <soc/gpio.h> #include <soc/smi.h> #include <assert.h> +#include <string.h> static int get_gpio_gevent(uint8_t gpio, const struct soc_amd_event *table, size_t items) @@ -298,3 +300,72 @@ void gpio_configure_pads_with_override(const struct soc_amd_gpio *base_cfg, program_gpios(c, 1); } } + +static void check_and_add_wake_gpio(int begin, int end, struct gpio_wake_state *state) +{ + int i; + uint32_t reg; + + for (i = begin; i < end; i++) { + reg = gpio_read32(i); + if (!(reg & GPIO_WAKE_STATUS)) + continue; + printk(BIOS_INFO, "GPIO %d woke system.\n", i); + if (state->num_valid_wake_gpios >= ARRAY_SIZE(state->wake_gpios)) + continue; + state->wake_gpios[state->num_valid_wake_gpios++] = i; + } +} + +static void check_gpios(uint32_t wake_stat, int bit_limit, int gpio_base, + struct gpio_wake_state *state) +{ + int i; + int begin; + int end; + + for (i = 0; i < bit_limit; i++) { + if (!(wake_stat & BIT(i))) + continue; + begin = gpio_base + i * 4; + end = begin + 4; + /* There is no gpio 63. */ + if (begin == 60) + end = 63; + check_and_add_wake_gpio(begin, end, state); + } +} + +void gpio_fill_wake_state(struct gpio_wake_state *state) +{ + /* Turn the wake registers into "gpio" index to conform to existing API. */ + const uint8_t stat0 = GPIO_WAKE_STAT_0 / sizeof(uint32_t); + const uint8_t stat1 = GPIO_WAKE_STAT_1 / sizeof(uint32_t); + const uint8_t control_switch = GPIO_MASTER_SWITCH / sizeof(uint32_t); + + /* Register fields and gpio availability need to be confirmed on other chipsets. */ + if (!CONFIG(SOC_AMD_PICASSO)) + dead_code(); + + memset(state, 0, sizeof(*state)); + + state->control_switch = gpio_read32(control_switch); + state->wake_stat[0] = gpio_read32(stat0); + state->wake_stat[1] = gpio_read32(stat1); + + printk(BIOS_INFO, "GPIO Control Switch: 0x%08x, Wake Stat 0: 0x%08x, Wake Stat 1: 0x%08x\n", + state->control_switch, state->wake_stat[0], state->wake_stat[1]); + + check_gpios(state->wake_stat[0], 32, 0, state); + check_gpios(state->wake_stat[1], 14, 128, state); +} + +void gpio_add_events(const struct gpio_wake_state *state) +{ + int i; + int end; + + end = MIN(state->num_valid_wake_gpios, ARRAY_SIZE(state->wake_gpios)); + for (i = 0; i < end; i++) + elog_add_event_wake(ELOG_WAKE_SOURCE_GPIO, state->wake_gpios[i]); +} diff --git a/src/soc/amd/common/block/include/amdblocks/gpio_banks.h b/src/soc/amd/common/block/include/amdblocks/gpio_banks.h index fdcd0f8ae4..b1663cf374 100644 --- a/src/soc/amd/common/block/include/amdblocks/gpio_banks.h +++ b/src/soc/amd/common/block/include/amdblocks/gpio_banks.h @@ -20,6 +20,23 @@ struct soc_amd_event { #define GPIO_MASTER_SWITCH 0xFC #define GPIO_MASK_STS_EN BIT(28) #define GPIO_INTERRUPT_EN BIT(30) +#define GPIO_WAKE_EN BIT(31) + +#define GPIO_WAKE_STAT_0 0x2F0 +#define GPIO_WAKE_STAT_1 0x2F4 +struct gpio_wake_state { + uint32_t control_switch; + uint32_t wake_stat[2]; + /* Number of wake_gpio with a valid setting. */ + uint32_t num_valid_wake_gpios; + /* GPIO index number that caused a wake. */ + uint8_t wake_gpios[16]; +}; + +/* Fill gpio_wake_state object for future event reporting. */ +void gpio_fill_wake_state(struct gpio_wake_state *state); +/* Add gpio events to the eventlog. */ +void gpio_add_events(const struct gpio_wake_state *state); #define GPIO_PIN_IN (1 << 0) /* for byte access */ #define GPIO_PIN_OUT (1 << 6) /* for byte access */ |