diff options
author | Richard Spiegel <richard.spiegel@amd.corp-partner.google.com> | 2018-04-20 16:50:12 -0700 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2018-05-27 01:03:28 +0000 |
commit | 2db06bba0fdeb2465108da487b0b2d1ecedef985 (patch) | |
tree | 49591ccccf5f171fd4e984cd517615ec8886b748 /src/soc/amd/stoneyridge/gpio.c | |
parent | 2aa13eff9d5df7c19898acecbcdb2fda1ec00d44 (diff) |
stoneyridge GPIO: Create and use PAD_INT for interrupt pins
The default interrupt control for GPIO pins within stoneyridge is for
edge triggered, high. However, sometimes these need to change, or maybe
the interrupt needs to be reported or delivered. This was the case of
platform grunt, where the interrupt related bits were being changed
afterwards. Ideally all the bits should be programmed through the same
procedure. Create several PAD_INT definitions (for general configuration,
for trigger configuration and for interrupt type configuration) and change
function sb_program_gpios() to accept the output from PAD_INT_XX and
program all the necessary bits while keeping compatibility with other
PAD_XX definitions.
BUG=b:72875858
TEST=Add code to report GPIO and interrupt configuration, build grunt and
record a baseline. Add new code, rebuild grunt and record a test output.
Compare baseline against test, there should be no change in GPIO or
interrupt programming.
Remove code that reports GPIO/interrupt configuration.
Change-Id: I3457543bdf64ec757fd82df53c83fdc1d03c1f22
Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com>
Reviewed-on: https://review.coreboot.org/25758
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/soc/amd/stoneyridge/gpio.c')
-rw-r--r-- | src/soc/amd/stoneyridge/gpio.c | 181 |
1 files changed, 173 insertions, 8 deletions
diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c index 4520df7a6f..1b7f0557df 100644 --- a/src/soc/amd/stoneyridge/gpio.c +++ b/src/soc/amd/stoneyridge/gpio.c @@ -19,6 +19,110 @@ #include <console/console.h> #include <gpio.h> #include <soc/gpio.h> +#include <assert.h> +#include <compiler.h> + +static const struct soc_amd_event gpio_event_table[] = { + { GPIO_1, GEVENT_19 }, + { GPIO_2, GEVENT_8 }, + { GPIO_3, GEVENT_2 }, + { GPIO_4, GEVENT_4 }, + { GPIO_5, GEVENT_7 }, + { GPIO_6, GEVENT_10 }, + { GPIO_7, GEVENT_11 }, + { GPIO_8, GEVENT_23 }, + { GPIO_9, GEVENT_22 }, + { GPIO_11, GEVENT_18 }, + { GPIO_13, GEVENT_21 }, + { GPIO_14, GEVENT_6 }, + { GPIO_15, GEVENT_20 }, + { GPIO_16, GEVENT_12 }, + { GPIO_17, GEVENT_13 }, + { GPIO_18, GEVENT_14 }, + { GPIO_21, GEVENT_5 }, + { GPIO_22, GEVENT_3 }, + { GPIO_23, GEVENT_16 }, + { GPIO_24, GEVENT_15 }, + { GPIO_65, GEVENT_0 }, + { GPIO_66, GEVENT_1 }, + { GPIO_68, GEVENT_9 }, + { GPIO_69, GEVENT_17 }, +}; + +static int get_gpio_gevent(uint8_t gpio) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(gpio_event_table); i++) { + if (gpio_event_table[i].gpio == gpio) + return (int)gpio_event_table[i].event; + } + return -1; +} + +static void mem_read_write32(uint32_t *address, uint32_t value, uint32_t mask) +{ + uint32_t reg32; + + value &= mask; + reg32 = read32(address); + reg32 &= ~mask; + reg32 |= value; + write32(address, reg32); +} + +__weak void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level) +{ + printk(BIOS_WARNING, "Warning: SMI disabled!\n"); +} + +static void program_smi(uint32_t flag, int gevent_num) +{ + uint32_t trigger; + + trigger = flag & FLAGS_TRIGGER_MASK; + /* + * Only level trigger is allowed for SMI. Trigger values are 0 + * through 3, with 0-1 being level trigger and 2-3 being edge + * trigger. GPIO_TRIGGER_EDGE_LOW is 2, so trigger has to be + * less than GPIO_TRIGGER_EDGE_LOW. + */ + assert(trigger < GPIO_TRIGGER_EDGE_LOW); + + if (trigger == GPIO_TRIGGER_LEVEL_HIGH) + configure_gevent_smi(gevent_num, SMI_MODE_SMI, + SMI_SCI_LVL_HIGH); + if (trigger == GPIO_TRIGGER_LEVEL_LOW) + configure_gevent_smi(gevent_num, SMI_MODE_SMI, + SMI_SCI_LVL_LOW); +} + +static void get_sci_config_bits(uint32_t flag, uint32_t *edge, uint32_t *level) +{ + uint32_t trigger; + + trigger = flag & FLAGS_TRIGGER_MASK; + switch (trigger) { + case GPIO_TRIGGER_LEVEL_LOW: + *edge = SCI_TRIGGER_LEVEL; + *level = 0; + break; + case GPIO_TRIGGER_LEVEL_HIGH: + *edge = SCI_TRIGGER_LEVEL; + *level = 1; + break; + case GPIO_TRIGGER_EDGE_LOW: + *edge = SCI_TRIGGER_EDGE; + *level = 0; + break; + case GPIO_TRIGGER_EDGE_HIGH: + *edge = SCI_TRIGGER_EDGE; + *level = 1; + break; + default: + break; + } +} static uintptr_t gpio_get_address(gpio_t gpio_num) { @@ -108,18 +212,79 @@ uint16_t gpio_acpi_pin(gpio_t gpio) return gpio; } -void gpio_set_interrupt(gpio_t gpio, uint32_t flags) +void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size) { - uintptr_t gpio_address = gpio_get_address(gpio); - uint32_t reg = read32((void *)gpio_address); + uint8_t *mux_ptr; + uint32_t *gpio_ptr; + uint32_t control, control_flags, edge_level, direction; + uint32_t mask, bit_edge, bit_level; + uint8_t mux, index, gpio; + int gevent_num; + + direction = 0; + edge_level = 0; + mask = 0; + for (index = 0; index < size; index++) { + gpio = gpio_list_ptr[index].gpio; + mux = gpio_list_ptr[index].function; + control = gpio_list_ptr[index].control; + control_flags = gpio_list_ptr[index].flags; - /* Clear registers that are being updated */ - reg &= ~(GPIO_TRIGGER_MASK | GPIO_ACTIVE_MASK | GPIO_INTERRUPT_MASK); + mux_ptr = (uint8_t *)(uintptr_t)(gpio + AMD_GPIO_MUX); + write8(mux_ptr, mux & AMD_GPIO_MUX_MASK); + gpio_ptr = (uint32_t *)gpio_get_address(gpio); - /* Clear any extra bits in the flags */ - flags &= (GPIO_TRIGGER_MASK | GPIO_ACTIVE_MASK | GPIO_INTERRUPT_MASK); + if (control_flags & GPIO_SPECIAL_FLAG) { + gevent_num = get_gpio_gevent(gpio); + if (gevent_num < 0) { + printk(BIOS_WARNING, "Warning: GPIO pin %d has" + " no associated gevent!\n", gpio); + continue; + } + switch (control_flags & GPIO_SPECIAL_MASK) { + case GPIO_DEBOUNCE_FLAG: + mem_read_write32(gpio_ptr, control, + GPIO_DEBOUNCE_MASK); + break; + case GPIO_WAKE_FLAG: + mem_read_write32(gpio_ptr, control, + INT_WAKE_MASK); + break; + case GPIO_INT_FLAG: + mem_read_write32(gpio_ptr, control, + AMD_GPIO_CONTROL_MASK); + break; + case GPIO_SMI_FLAG: + mem_read_write32(gpio_ptr, control, + INT_SCI_SMI_MASK); + program_smi(control_flags, gevent_num); + break; + case GPIO_SCI_FLAG: + mem_read_write32(gpio_ptr, control, + INT_SCI_SMI_MASK); + get_sci_config_bits(control_flags, &bit_edge, + &bit_level); + edge_level |= bit_edge << gevent_num; + direction |= bit_level << gevent_num; + mask |= (1 << gevent_num); + break; + default: + printk(BIOS_WARNING, "Error, flags 0x%08x\n", + control_flags); + break; + } + } else { + mem_read_write32(gpio_ptr, control, + AMD_GPIO_CONTROL_MASK); + } + } + /* Set all SCI trigger direction (high/low) */ + mem_read_write32((uint32_t *)(uintptr_t)(APU_SMI_BASE + SMI_SCI_TRIG), + direction, mask); - write32((void *)gpio_address, reg | flags); + /* Set all SCI trigger level (edge/level) */ + mem_read_write32((uint32_t *)(uintptr_t)(APU_SMI_BASE + SMI_SCI_LEVEL), + edge_level, mask); } int gpio_interrupt_status(gpio_t gpio) |