aboutsummaryrefslogtreecommitdiff
path: root/src/soc/amd/stoneyridge/gpio.c
diff options
context:
space:
mode:
authorMarshall Dawson <marshalldawson3rd@gmail.com>2019-05-02 17:27:57 -0600
committerMartin Roth <martinroth@google.com>2019-06-06 17:57:40 +0000
commit251d305e73f76ca3b63654273f3b2bb3de775457 (patch)
tree76cf206b9b73033c21569005f12f80f1df7bbcbf /src/soc/amd/stoneyridge/gpio.c
parenteb5b0d05a71ec04d69699edebb6e71be2bb6ed09 (diff)
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 <marshalldawson3rd@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32651 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.c295
1 files changed, 11 insertions, 284 deletions
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 <device/mmio.h>
-#include <device/device.h>
-#include <console/console.h>
-#include <gpio.h>
+#include <stdint.h>
+#include <amdblocks/gpio_banks.h>
#include <amdblocks/acpimmio.h>
#include <soc/gpio.h>
-#include <assert.h>
-#include "chip.h"
+#include <soc/smi.h>
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);
}