From 251d305e73f76ca3b63654273f3b2bb3de775457 Mon Sep 17 00:00:00 2001 From: Marshall Dawson Date: Thu, 2 May 2019 17:27:57 -0600 Subject: soc/amd/stoneyridge: Move GPIO support to common The banked GPIO functionality in the AcpiMmio block has been consistent since the Mullins product. Move the basic support into a common directory. Each product's pin availability, MUXes, and other details must remain specific to the product. The relocated source also drops the weak configure_gevent_smi() that reports SMI is not available. The stoneyridge port relies on SMI to do its initialization, similar to modern soc/intel devices. This is the plan for future soc/amd ports, so make a missing function a build error instead of a runtime warning. BUG=b:131682806 Change-Id: I9cda00210a74de2bd1308ad43e2b867d24a67845 Signed-off-by: Marshall Dawson Reviewed-on: https://review.coreboot.org/c/coreboot/+/32651 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth --- src/soc/amd/stoneyridge/gpio.c | 295 ++--------------------------------------- 1 file changed, 11 insertions(+), 284 deletions(-) (limited to 'src/soc/amd/stoneyridge/gpio.c') diff --git a/src/soc/amd/stoneyridge/gpio.c b/src/soc/amd/stoneyridge/gpio.c index 7c9680582c..f63a0d93a4 100644 --- a/src/soc/amd/stoneyridge/gpio.c +++ b/src/soc/amd/stoneyridge/gpio.c @@ -15,14 +15,11 @@ * GNU General Public License for more details. */ -#include -#include -#include -#include +#include +#include #include #include -#include -#include "chip.h" +#include static const struct soc_amd_event gpio_event_table[] = { { GPIO_1, GEVENT_19 }, @@ -51,290 +48,20 @@ static const struct soc_amd_event gpio_event_table[] = { { 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 route_sci(uint8_t event) +void soc_route_sci(uint8_t event) { smi_write8(SMI_SCI_MAP(event), event); } -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; - } -} - -uintptr_t gpio_get_address(gpio_t gpio_num) -{ - uintptr_t gpio_address; - - if (gpio_num < 64) - gpio_address = GPIO_BANK0_CONTROL(gpio_num); - else if (gpio_num < 128) - gpio_address = GPIO_BANK1_CONTROL(gpio_num); - else - gpio_address = GPIO_BANK2_CONTROL(gpio_num); - - return gpio_address; -} - -int gpio_get(gpio_t gpio_num) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - - return !!(reg & GPIO_PIN_STS); -} - -void gpio_set(gpio_t gpio_num, int value) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - reg &= ~GPIO_OUTPUT_MASK; - reg |= !!value << GPIO_OUTPUT_SHIFT; - write32((void *)gpio_address, reg); -} - -void gpio_input_pulldown(gpio_t gpio_num) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - reg &= ~GPIO_PULLUP_ENABLE; - reg |= GPIO_PULLDOWN_ENABLE; - write32((void *)gpio_address, reg); -} - -void gpio_input_pullup(gpio_t gpio_num) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - reg &= ~GPIO_PULLDOWN_ENABLE; - reg |= GPIO_PULLUP_ENABLE; - write32((void *)gpio_address, reg); -} - -void gpio_input(gpio_t gpio_num) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - reg &= ~GPIO_OUTPUT_ENABLE; - write32((void *)gpio_address, reg); -} - -void gpio_output(gpio_t gpio_num, int value) -{ - uint32_t reg; - uintptr_t gpio_address = gpio_get_address(gpio_num); - - reg = read32((void *)gpio_address); - reg |= GPIO_OUTPUT_ENABLE; - write32((void *)gpio_address, reg); - gpio_set(gpio_num, value); -} - -const char *gpio_acpi_path(gpio_t gpio) +void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items) { - return "\\_SB.GPIO"; + *table = gpio_event_table; + *items = ARRAY_SIZE(gpio_event_table); } -uint16_t gpio_acpi_pin(gpio_t gpio) +void soc_gpio_hook(uint8_t gpio, uint8_t mux) { - return gpio; -} - -void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size) -{ - uint32_t *gpio_ptr, *inter_master; - uint32_t control, control_flags, edge_level, direction; - uint32_t mask, bit_edge, bit_level; - uint8_t mux, index, gpio; - int gevent_num; - - inter_master = (uint32_t *)(uintptr_t)(ACPIMMIO_GPIO0_BASE - + GPIO_MASTER_SWITCH); - direction = 0; - edge_level = 0; - mask = 0; - - /* - * Disable blocking wake/interrupt status generation while updating - * debounce registers. Otherwise when a debounce register is updated - * the whole GPIO controller will zero out all interrupt enable status - * bits while the delay happens. This could cause us to drop the bits - * due to the read-modify-write that happens on each register. - * - * Additionally disable interrupt generation so we don't get any - * spurious interrupts while updating the registers. - */ - mem_read_write32(inter_master, 0, GPIO_MASK_STS_EN | GPIO_INTERRUPT_EN); - - 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; - - iomux_write8(gpio, mux & AMD_GPIO_MUX_MASK); - iomux_read8(gpio); /* Flush posted write */ - /* special case if pin 2 is assigned to wake */ - if ((gpio == 2) && !(mux & AMD_GPIO_MUX_MASK)) - route_sci(GPIO_2_EVENT); - gpio_ptr = (uint32_t *)gpio_get_address(gpio); - - 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); - route_sci(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); - } - } - - /* - * Re-enable interrupt status generation. - * - * We leave MASK_STATUS disabled because the kernel may reconfigure the - * debounce registers while the drivers load. This will cause interrupts - * to be missed during boot. - */ - mem_read_write32(inter_master, GPIO_INTERRUPT_EN, GPIO_INTERRUPT_EN); - - /* Set all SCI trigger direction (high/low) */ - mem_read_write32((uint32_t *) - (uintptr_t)(ACPIMMIO_SMI_BASE + SMI_SCI_TRIG), - direction, mask); - - /* Set all SCI trigger level (edge/level) */ - mem_read_write32((uint32_t *) - (uintptr_t)(ACPIMMIO_SMI_BASE + SMI_SCI_LEVEL), - edge_level, mask); -} - -int gpio_interrupt_status(gpio_t gpio) -{ - uintptr_t gpio_address = gpio_get_address(gpio); - uint32_t reg = read32((void *)gpio_address); - - if (reg & GPIO_INT_STATUS) { - /* Clear interrupt status, preserve wake status */ - reg &= ~GPIO_WAKE_STATUS; - write32((void *)gpio_address, reg); - return 1; - } - - return 0; + /* Always program Gevent when WAKE_L_AGPIO2 is configured as WAKE_L */ + if ((gpio == 2) && !(mux & AMD_GPIO_MUX_MASK)) + soc_route_sci(GPIO_2_EVENT); } -- cgit v1.2.3