diff options
author | Marshall Dawson <marshalldawson3rd@gmail.com> | 2019-05-02 17:27:57 -0600 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2019-06-06 17:57:40 +0000 |
commit | 251d305e73f76ca3b63654273f3b2bb3de775457 (patch) | |
tree | 76cf206b9b73033c21569005f12f80f1df7bbcbf /src/soc | |
parent | eb5b0d05a71ec04d69699edebb6e71be2bb6ed09 (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')
-rw-r--r-- | src/soc/amd/common/acpi/gpio_bank_lib.asl (renamed from src/soc/amd/stoneyridge/acpi/gpio_lib.asl) | 0 | ||||
-rw-r--r-- | src/soc/amd/common/block/gpio_banks/Kconfig | 8 | ||||
-rw-r--r-- | src/soc/amd/common/block/gpio_banks/Makefile.inc | 6 | ||||
-rw-r--r-- | src/soc/amd/common/block/gpio_banks/gpio.c | 310 | ||||
-rw-r--r-- | src/soc/amd/common/block/include/amdblocks/gpio_banks.h | 308 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/Kconfig | 1 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/acpi.c | 8 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/acpi/soc.asl | 2 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/gpio.c | 295 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/i2c.c | 2 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/gpio.h | 286 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/smi.h | 1 |
12 files changed, 657 insertions, 570 deletions
diff --git a/src/soc/amd/stoneyridge/acpi/gpio_lib.asl b/src/soc/amd/common/acpi/gpio_bank_lib.asl index 8185c35ac5..8185c35ac5 100644 --- a/src/soc/amd/stoneyridge/acpi/gpio_lib.asl +++ b/src/soc/amd/common/acpi/gpio_bank_lib.asl diff --git a/src/soc/amd/common/block/gpio_banks/Kconfig b/src/soc/amd/common/block/gpio_banks/Kconfig new file mode 100644 index 0000000000..115aa2cc52 --- /dev/null +++ b/src/soc/amd/common/block/gpio_banks/Kconfig @@ -0,0 +1,8 @@ +config SOC_AMD_COMMON_BLOCK_BANKED_GPIOS + bool + depends on SOC_AMD_COMMON_BLOCK_ACPIMMIO + default n + help + Select this option to use the newer style banks of GPIO signals. + These are at offsets +0x1500, +0x1600, and +0x1700 from the AcpiMmio + base. diff --git a/src/soc/amd/common/block/gpio_banks/Makefile.inc b/src/soc/amd/common/block/gpio_banks/Makefile.inc new file mode 100644 index 0000000000..f1555b12b8 --- /dev/null +++ b/src/soc/amd/common/block/gpio_banks/Makefile.inc @@ -0,0 +1,6 @@ +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c +verstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c +postcar-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_BANKED_GPIOS) += gpio.c diff --git a/src/soc/amd/common/block/gpio_banks/gpio.c b/src/soc/amd/common/block/gpio_banks/gpio.c new file mode 100644 index 0000000000..17e3de09e3 --- /dev/null +++ b/src/soc/amd/common/block/gpio_banks/gpio.c @@ -0,0 +1,310 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 Google Inc. + * Copyright (C) 2015 Intel Corporation + * Copyright (C) 2017 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <device/mmio.h> +#include <device/device.h> +#include <console/console.h> +#include <gpio.h> +#include <amdblocks/acpimmio.h> +#include <soc/gpio.h> +#include <soc/smi.h> +#include <assert.h> + +static int get_gpio_gevent(uint8_t gpio, const struct soc_amd_event *table, + size_t items) +{ + int i; + + for (i = 0; i < items; i++) { + if ((table + i)->gpio == gpio) + return (int)(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); +} + +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; + } +} + +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) +{ + return "\\_SB.GPIO"; +} + +uint16_t gpio_acpi_pin(gpio_t gpio) +{ + return gpio; +} + +__weak void soc_gpio_hook(uint8_t gpio, uint8_t mux) {} + +void 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; + const struct soc_amd_event *gev_tbl; + size_t gev_items; + + 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); + + soc_get_gpio_event_table(&gev_tbl, &gev_items); + + 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 */ + + soc_gpio_hook(gpio, mux); + + gpio_ptr = (uint32_t *)gpio_get_address(gpio); + + if (control_flags & GPIO_SPECIAL_FLAG) { + gevent_num = get_gpio_gevent(gpio, gev_tbl, gev_items); + 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); + soc_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; +} diff --git a/src/soc/amd/common/block/include/amdblocks/gpio_banks.h b/src/soc/amd/common/block/include/amdblocks/gpio_banks.h new file mode 100644 index 0000000000..da841347fb --- /dev/null +++ b/src/soc/amd/common/block/include/amdblocks/gpio_banks.h @@ -0,0 +1,308 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AMDBLOCK_GPIO_BANKS_H__ +#define __AMDBLOCK_GPIO_BANKS_H__ + +#include <stdint.h> +#include <stddef.h> + +struct soc_amd_gpio { + uint8_t gpio; + uint8_t function; + uint32_t control; + uint32_t flags; +}; + +struct soc_amd_event { + uint8_t gpio; + uint8_t event; +}; + +#define GPIO_BANK0_CONTROL(gpio) (ACPIMMIO_GPIO0_BASE + ((gpio) * 4)) +#define GPIO_BANK1_CONTROL(gpio) (ACPIMMIO_GPIO1_BASE + (((gpio) - 64) * 4)) +#define GPIO_BANK2_CONTROL(gpio) (ACPIMMIO_GPIO2_BASE + (((gpio) - 128) * 4)) + +#define GPIO_MASTER_SWITCH 0xFC +#define GPIO_MASK_STS_EN BIT(28) +#define GPIO_INTERRUPT_EN BIT(30) + +#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) + +#define GPIO_ACTIVE_HIGH (0 << 9) +#define GPIO_ACTIVE_LOW (1 << 9) +#define GPIO_ACTIVE_BOTH (2 << 9) +#define GPIO_ACTIVE_MASK (3 << 9) + +#define GPIO_INT_STATUS_EN (1 << 11) +#define GPIO_INT_DELIVERY_EN (1 << 12) +#define GPIO_INTERRUPT_MASK (3 << 11) +#define GPIO_S0I3_WAKE_EN (1 << 13) +#define GPIO_S3_WAKE_EN (1 << 14) +#define GPIO_S4_S5_WAKE_EN (1 << 15) + +#define GPIO_PIN_STS (1 << 16) +#define GPIO_PULLUP_ENABLE (1 << 20) +#define GPIO_PULLDOWN_ENABLE (1 << 21) +#define GPIO_OUTPUT_SHIFT 22 +#define GPIO_OUTPUT_MASK (1 << GPIO_OUTPUT_SHIFT) +#define GPIO_OUTPUT_VALUE (1 << GPIO_OUTPUT_SHIFT) +#define GPIO_OUTPUT_ENABLE (1 << 23) + +#define GPIO_INT_STATUS (1 << 28) +#define GPIO_WAKE_STATUS (1 << 29) + +enum { + GEVENT_0, + GEVENT_1, + GEVENT_2, + GEVENT_3, + GEVENT_4, + GEVENT_5, + GEVENT_6, + GEVENT_7, + GEVENT_8, + GEVENT_9, + GEVENT_10, + GEVENT_11, + GEVENT_12, + GEVENT_13, + GEVENT_14, + GEVENT_15, + GEVENT_16, + GEVENT_17, + GEVENT_18, + GEVENT_19, + GEVENT_20, + GEVENT_21, + GEVENT_22, + GEVENT_23, + GEVENT_24, + GEVENT_25, + GEVENT_26, + GEVENT_27, + GEVENT_28, + GEVENT_29, + GEVENT_30, + GEVENT_31, +}; + +#define GPIO_OUTPUT_OUT_HIGH (GPIO_OUTPUT_ENABLE | GPIO_OUTPUT_VALUE) +#define GPIO_OUTPUT_OUT_LOW GPIO_OUTPUT_ENABLE + +#define GPIO_PULL_PULL_UP GPIO_PULLUP_ENABLE +#define GPIO_PULL_PULL_DOWN GPIO_PULLDOWN_ENABLE +#define GPIO_PULL_PULL_NONE 0 + +#define AMD_GPIO_CONTROL_MASK 0x00f4ff00 +#define AMD_GPIO_MUX_MASK 0x03 + +/* Definitions for PAD_INT. */ +#define GPIO_INT_EDGE_HIGH (GPIO_ACTIVE_HIGH | GPIO_EDGE_TRIG) +#define GPIO_INT_EDGE_LOW (GPIO_ACTIVE_LOW | GPIO_EDGE_TRIG) +#define GPIO_INT_BOTH_EDGES (GPIO_ACTIVE_BOTH | GPIO_EDGE_TRIG) +#define GPIO_INT_LEVEL_HIGH (GPIO_ACTIVE_HIGH | GPIO_LEVEL_TRIG) +#define GPIO_INT_LEVEL_LOW (GPIO_ACTIVE_LOW | GPIO_LEVEL_TRIG) + +enum { + GPIO_TRIGGER_LEVEL_LOW, + GPIO_TRIGGER_LEVEL_HIGH, + GPIO_TRIGGER_EDGE_LOW, + GPIO_TRIGGER_EDGE_HIGH, +}; + +#define GPIO_TRIGGER_INVALID -1 +#define SCI_TRIGGER_EDGE 0 +#define SCI_TRIGGER_LEVEL 1 + +#define GPIO_SPECIAL_FLAG (1 << 31) +#define GPIO_DEBOUNCE_FLAG (1 << 30) +#define GPIO_WAKE_FLAG (1 << 29) +#define GPIO_INT_FLAG (1 << 28) +#define GPIO_SMI_FLAG (1 << 27) +#define GPIO_SCI_FLAG (1 << 26) +#define GPIO_FLAG_DEBOUNCE (GPIO_SPECIAL_FLAG | GPIO_DEBOUNCE_FLAG) +#define GPIO_FLAG_WAKE (GPIO_SPECIAL_FLAG | GPIO_WAKE_FLAG) +#define GPIO_FLAG_INT (GPIO_SPECIAL_FLAG | GPIO_INT_FLAG) +#define GPIO_FLAG_SCI (GPIO_SPECIAL_FLAG | GPIO_SCI_FLAG) +#define GPIO_FLAG_SMI (GPIO_SPECIAL_FLAG | GPIO_SMI_FLAG) + +#define FLAGS_TRIGGER_MASK 0x00000003 +#define GPIO_SPECIAL_MASK 0x7c000000 +#define GPIO_DEBOUNCE_MASK 0x000000ff +#define INT_TRIGGER_MASK 0x00000700 +#define INT_WAKE_MASK 0x0000e700 +#define INT_SCI_SMI_MASK 0x00f40000 + +#define IN_GLITCH_SHIFT 5 +#define GLITCH_LOW 1 +#define GLITCH_HIGH 2 +#define GLITCH_NONE 3 +#define GPIO_IN_PRESERVE_LOW_GLITCH (GLITCH_LOW << IN_GLITCH_SHIFT) +#define GPIO_IN_PRESERVE_HIGH_GLITCH (GLITCH_HIGH << IN_GLITCH_SHIFT) +#define GPIO_IN_REMOVE_GLITCH (GLITCH_NONE << IN_GLITCH_SHIFT) + +#define GPIO_TIMEBASE_61uS 0 +#define GPIO_TIMEBASE_183uS (1 << 4) +#define GPIO_TIMEBASE_15560uS (1 << 7) +#define GPIO_TIMEBASE_62440uS (GPIO_TIMEBASE_183uS | \ + GPIO_TIMEBASE_15560uS) +#define GPIO_IN_DEBOUNCE_DISABLED (0 | GPIO_TIMEBASE_61uS) +#define GPIO_IN_60uS (1 | GPIO_TIMEBASE_61uS) +#define GPIO_IN_120uS (2 | GPIO_TIMEBASE_61uS) +#define GPIO_IN_200uS (3 | GPIO_TIMEBASE_61uS) +#define GPIO_IN_500uS (8 | GPIO_TIMEBASE_61uS) +#define GPIO_IN_1mS (5 | GPIO_TIMEBASE_183uS) +#define GPIO_IN_2mS (11 | GPIO_TIMEBASE_183uS) +#define GPIO_IN_15mS (1 | GPIO_TIMEBASE_15560uS) +#define GPIO_IN_50mS (3 | GPIO_TIMEBASE_15560uS) +#define GPIO_IN_100mS (6 | GPIO_TIMEBASE_15560uS) +#define GPIO_IN_200mS (13 | GPIO_TIMEBASE_15560uS) +#define GPIO_IN_500mS (8 | GPIO_TIMEBASE_62440uS) + +#define GPIO_EVENT_INT_STATUS GPIO_INT_STATUS_EN +#define GPIO_EVENT_INT_DELIVER GPIO_INT_DELIVERY_EN +#define GPIO_EVENT_INT_STATUS_DELIVER (GPIO_INT_STATUS_EN | \ + GPIO_INT_DELIVERY_EN) +#define GPIO_WAKE_S0i3 (1 << 13) +#define GPIO_WAKE_S3 (1 << 14) +#define GPIO_WAKE_S4_S5 (1 << 15) +#define GPIO_WAKE_S0i3_S4_S5 (GPIO_WAKE_S0i3 | GPIO_WAKE_S4_S5) +#define GPIO_WAKE_S3_S4_S5 (GPIO_WAKE_S3 | GPIO_WAKE_S4_S5) + +/* + * Several macros are available to declare programming of GPIO pins, and if + * needed, more than 1 macro can be used for any pin. However, some macros + * will have no effect if combined. For example debounce only affects input + * or one of the interrupts. Some macros should not be combined, such as SMI + * and regular interrupt. The defined macros and their parameters are: + * PAD_NF Define native alternate function for the pin. + * pin the pin to be programmed + * function the native function + * pull pull up, pull down or no pull + * PAD_GPI The pin is a GPIO input + * pin the pin to be programmed + * pull pull up, pull down or no pull + * PAD_GPO The pin is a GPIO output + * pin the pin to be programmed + * direction high or low + * PAD_INT The pin is regular interrupt that works while booting + * pin the pin to be programmed + * pull pull up, pull down or no pull + * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES + * action STATUS, DELIVER, STATUS_DELIVER + * PAD_SCI The pin is a SCI source + * pin the pin to be programmed + * pull pull up, pull down or no pull + * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH + * PAD_SMI The pin is a SMI source + * pin the pin to be programmed + * pull pull up, pull down or no pull + * trigger LEVEL_LOW, LEVEL_HIGH + * PAD_WAKE The pin can wake, use after PAD_INT or PAD_SCI + * pin the pin to be programmed + * pull pull up, pull down or no pull + * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES + * type S0i3, S3, S4_S5 or S4_S5 combinations (S0i3_S3 invalid) + * PAD_DEBOUNCE The input or interrupt will be debounced, invalid after + * PAD_NF + * pin the pin to be programmed + * debounce_type preserve low glitch, preserve high glitch, no glitch + * debounce_time the debounce time + */ + +/* Native function pad configuration */ +#define PAD_NF(pin, func, pull) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## func, \ + .control = GPIO_PULL ## _ ## pull, \ + .flags = 0 } +/* General purpose input pad configuration */ +#define PAD_GPI(pin, pull) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = GPIO_PULL ## _ ## pull, \ + .flags = 0 } +/* General purpose output pad configuration */ +#define PAD_GPO(pin, direction) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = GPIO_OUTPUT ## _OUT_ ## direction, \ + .flags = 0 } +/* Auxiliary macro for legacy interrupt and wake */ +#define PAD_AUX1(pull, trigger) (GPIO_PULL ## _ ## pull | \ + GPIO_INT ## _ ## trigger) +/* Legacy interrupt pad configuration */ +#define PAD_INT(pin, pull, trigger, action) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = (PAD_AUX1(pull, trigger) | \ + GPIO_EVENT_INT ## _ ## action), \ + .flags = GPIO_FLAG_INT } +/* Auxiliary macro for SCI and SMI */ +#define PAD_AUX2(trigger, flag) (GPIO_TRIGGER ## _ ## trigger | flag) +/* SCI pad configuration */ +#define PAD_SCI(pin, pull, trigger) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = GPIO_PULL ## _ ## pull, \ + .flags = PAD_AUX2(trigger, GPIO_FLAG_SCI) } +/* SMI pad configuration */ +#define PAD_SMI(pin, pull, trigger) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = GPIO_PULL ## _ ## pull, \ + .flags = PAD_AUX2(trigger, GPIO_FLAG_SMI) } +/* WAKE pad configuration */ +#define PAD_WAKE(pin, pull, trigger, type) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = (PAD_AUX1(pull, trigger) | \ + GPIO_WAKE ## _ ## type), \ + .flags = GPIO_FLAG_WAKE } +/* pin debounce configuration */ +#define PAD_DEBOUNCE(pin, type, time) \ + { .gpio = (pin), \ + .function = pin ## _IOMUX_ ## GPIOxx, \ + .control = (GPIO_IN ## _ ## type | GPIO_IN ## _ ## time), \ + .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 + * + * @param gpio_list_ptr = pointer to array of gpio configurations + * @param size = number of entries in array + * + * @return none + */ +void program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size); +/* Return the interrupt status and clear if set. */ +int gpio_interrupt_status(gpio_t gpio); +/* Implemented by soc, provides table of avaialable GPIO mapping to Gevents */ +void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items); +/* May be implemented by soc to handle special cases */ +void soc_gpio_hook(uint8_t gpio, uint8_t mux); + +#endif /* __AMDBLOCK_GPIO_BANKS_H__ */ diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index d4e1feb251..5333f5933a 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -47,6 +47,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_AMD_COMMON select SOC_AMD_COMMON_BLOCK select SOC_AMD_COMMON_BLOCK_ACPIMMIO + select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS select SOC_AMD_COMMON_BLOCK_PCI select SOC_AMD_COMMON_BLOCK_PI select SOC_AMD_COMMON_BLOCK_PSP diff --git a/src/soc/amd/stoneyridge/acpi.c b/src/soc/amd/stoneyridge/acpi.c index 4f11ea227a..2cd9632424 100644 --- a/src/soc/amd/stoneyridge/acpi.c +++ b/src/soc/amd/stoneyridge/acpi.c @@ -317,9 +317,9 @@ static void acpigen_soc_get_gpio_in_local5(uintptr_t addr) static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask) { - if (gpio_num >= GPIO_TOTAL_PINS) { + if (gpio_num >= SOC_GPIO_TOTAL_PINS) { printk(BIOS_WARNING, "Warning: Pin %d should be smaller than" - " %d\n", gpio_num, GPIO_TOTAL_PINS); + " %d\n", gpio_num, SOC_GPIO_TOTAL_PINS); return -1; } uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num); @@ -347,9 +347,9 @@ static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask) static int acpigen_soc_set_gpio_val(unsigned int gpio_num, uint32_t val) { - if (gpio_num >= GPIO_TOTAL_PINS) { + if (gpio_num >= SOC_GPIO_TOTAL_PINS) { printk(BIOS_WARNING, "Warning: Pin %d should be smaller than" - " %d\n", gpio_num, GPIO_TOTAL_PINS); + " %d\n", gpio_num, SOC_GPIO_TOTAL_PINS); return -1; } uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num); diff --git a/src/soc/amd/stoneyridge/acpi/soc.asl b/src/soc/amd/stoneyridge/acpi/soc.asl index 6fd838a56d..52c7ee6c00 100644 --- a/src/soc/amd/stoneyridge/acpi/soc.asl +++ b/src/soc/amd/stoneyridge/acpi/soc.asl @@ -28,4 +28,4 @@ Device(PCI0) { #include "sb_fch.asl" /* Add GPIO library */ -#include <gpio_lib.asl> +#include <soc/amd/common/acpi/gpio_bank_lib.asl> 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); } diff --git a/src/soc/amd/stoneyridge/i2c.c b/src/soc/amd/stoneyridge/i2c.c index c3e5539e19..7f65a4f3f3 100644 --- a/src/soc/amd/stoneyridge/i2c.c +++ b/src/soc/amd/stoneyridge/i2c.c @@ -203,7 +203,7 @@ void sb_reset_i2c_slaves(void) /* Save and reprogram I2C SCL pins */ for (i = 0; i < saved_pins_count; i++) save_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]); - sb_program_gpios(i2c_2_gpi, saved_pins_count); + program_gpios(i2c_2_gpi, saved_pins_count); /* * Toggle SCL back and forth 9 times under 100KHz. A single read is diff --git a/src/soc/amd/stoneyridge/include/soc/gpio.h b/src/soc/amd/stoneyridge/include/soc/gpio.h index 26d0336d0a..d8774f051a 100644 --- a/src/soc/amd/stoneyridge/include/soc/gpio.h +++ b/src/soc/amd/stoneyridge/include/soc/gpio.h @@ -21,59 +21,13 @@ #ifndef __ACPI__ #include <soc/iomap.h> -#include <soc/smi.h> -#include <types.h> +#include <amdblocks/gpio_banks.h> -struct soc_amd_gpio { - uint8_t gpio; - uint8_t function; - uint32_t control; - uint32_t flags; -}; +/* The following sections describe only the GPIOs defined for this SOC */ -struct soc_amd_event { - uint8_t gpio; - uint8_t event; -}; +#define SOC_GPIO_TOTAL_PINS 149 -#define GPIO_MASTER_SWITCH 0xFC -#define GPIO_MASK_STS_EN BIT(28) -#define GPIO_INTERRUPT_EN BIT(30) - -#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) - -#define GPIO_ACTIVE_HIGH (0 << 9) -#define GPIO_ACTIVE_LOW (1 << 9) -#define GPIO_ACTIVE_BOTH (2 << 9) -#define GPIO_ACTIVE_MASK (3 << 9) - -#define GPIO_INT_STATUS_EN (1 << 11) -#define GPIO_INT_DELIVERY_EN (1 << 12) -#define GPIO_INTERRUPT_MASK (3 << 11) -#define GPIO_S0I3_WAKE_EN (1 << 13) -#define GPIO_S3_WAKE_EN (1 << 14) -#define GPIO_S4_S5_WAKE_EN (1 << 15) - -#define GPIO_PIN_STS (1 << 16) -#define GPIO_PULLUP_ENABLE (1 << 20) -#define GPIO_PULLDOWN_ENABLE (1 << 21) -#define GPIO_OUTPUT_SHIFT 22 -#define GPIO_OUTPUT_MASK (1 << GPIO_OUTPUT_SHIFT) -#define GPIO_OUTPUT_VALUE (1 << GPIO_OUTPUT_SHIFT) -#define GPIO_OUTPUT_ENABLE (1 << 23) - -#define GPIO_INT_STATUS (1 << 28) -#define GPIO_WAKE_STATUS (1 << 29) - -/* GPIO_0 - GPIO_62 */ -#define GPIO_BANK0_CONTROL(gpio) \ - (AMD_SB_ACPI_MMIO_ADDR + 0x1500 + ((gpio) * 4)) +/* Bank 0: GPIO_0 - GPIO_62 */ #define GPIO_0 0 #define GPIO_1 1 #define GPIO_2 2 @@ -105,9 +59,7 @@ struct soc_amd_event { #define GPIO_40 40 #define GPIO_42 42 -/* GPIO_64 - GPIO_127 */ -#define GPIO_BANK1_CONTROL(gpio) \ - (AMD_SB_ACPI_MMIO_ADDR + 0x1600 + (((gpio) - 64) * 4)) +/* Bank 1: GPIO_64 - GPIO_127 */ #define GPIO_64 64 #define GPIO_65 65 #define GPIO_66 66 @@ -150,10 +102,7 @@ struct soc_amd_event { #define GPIO_122 122 #define GPIO_126 126 -/* GPIO_128 - GPIO_183 */ -#define GPIO_BANK2_CONTROL(gpio) \ - (AMD_SB_ACPI_MMIO_ADDR + 0x1700 + (((gpio) - 128) * 4)) -/* GPIO_128 Reserved */ +/* Bank 2: GPIO_128 - GPIO_183 */ #define GPIO_129 129 #define GPIO_130 130 #define GPIO_131 131 @@ -353,230 +302,7 @@ struct soc_amd_event { #define GPIO_148_IOMUX_I2C1_SDA 0 #define GPIO_148_IOMUX_GPIOxx 1 -enum { - GEVENT_0, - GEVENT_1, - GEVENT_2, - GEVENT_3, - GEVENT_4, - GEVENT_5, - GEVENT_6, - GEVENT_7, - GEVENT_8, - GEVENT_9, - GEVENT_10, - GEVENT_11, - GEVENT_12, - GEVENT_13, - GEVENT_14, - GEVENT_15, - GEVENT_16, - GEVENT_17, - GEVENT_18, - GEVENT_19, - GEVENT_20, - GEVENT_21, - GEVENT_22, - GEVENT_23, -}; #define GPIO_2_EVENT GEVENT_8 -#define GPIO_OUTPUT_OUT_HIGH (GPIO_OUTPUT_ENABLE | GPIO_OUTPUT_VALUE) -#define GPIO_OUTPUT_OUT_LOW GPIO_OUTPUT_ENABLE - -#define GPIO_PULL_PULL_UP GPIO_PULLUP_ENABLE -#define GPIO_PULL_PULL_DOWN GPIO_PULLDOWN_ENABLE -#define GPIO_PULL_PULL_NONE 0 - -#define AMD_GPIO_CONTROL_MASK 0x00f4ff00 -#define AMD_GPIO_MUX_MASK 0x03 - -/* Definitions for PAD_INT. */ -#define GPIO_INT_EDGE_HIGH (GPIO_ACTIVE_HIGH | GPIO_EDGE_TRIG) -#define GPIO_INT_EDGE_LOW (GPIO_ACTIVE_LOW | GPIO_EDGE_TRIG) -#define GPIO_INT_BOTH_EDGES (GPIO_ACTIVE_BOTH | GPIO_EDGE_TRIG) -#define GPIO_INT_LEVEL_HIGH (GPIO_ACTIVE_HIGH | GPIO_LEVEL_TRIG) -#define GPIO_INT_LEVEL_LOW (GPIO_ACTIVE_LOW | GPIO_LEVEL_TRIG) - -enum { - GPIO_TRIGGER_LEVEL_LOW, - GPIO_TRIGGER_LEVEL_HIGH, - GPIO_TRIGGER_EDGE_LOW, - GPIO_TRIGGER_EDGE_HIGH, -}; - -#define GPIO_TRIGGER_INVALID -1 -#define SCI_TRIGGER_EDGE 0 -#define SCI_TRIGGER_LEVEL 1 - -#define GPIO_SPECIAL_FLAG (1 << 31) -#define GPIO_DEBOUNCE_FLAG (1 << 30) -#define GPIO_WAKE_FLAG (1 << 29) -#define GPIO_INT_FLAG (1 << 28) -#define GPIO_SMI_FLAG (1 << 27) -#define GPIO_SCI_FLAG (1 << 26) -#define GPIO_FLAG_DEBOUNCE (GPIO_SPECIAL_FLAG | GPIO_DEBOUNCE_FLAG) -#define GPIO_FLAG_WAKE (GPIO_SPECIAL_FLAG | GPIO_WAKE_FLAG) -#define GPIO_FLAG_INT (GPIO_SPECIAL_FLAG | GPIO_INT_FLAG) -#define GPIO_FLAG_SCI (GPIO_SPECIAL_FLAG | GPIO_SCI_FLAG) -#define GPIO_FLAG_SMI (GPIO_SPECIAL_FLAG | GPIO_SMI_FLAG) - -#define FLAGS_TRIGGER_MASK 0x00000003 -#define GPIO_SPECIAL_MASK 0x7c000000 -#define GPIO_DEBOUNCE_MASK 0x000000ff -#define INT_TRIGGER_MASK 0x00000700 -#define INT_WAKE_MASK 0x0000e700 -#define INT_SCI_SMI_MASK 0x00f40000 - -#define IN_GLITCH_SHIFT 5 -#define GLITCH_LOW 1 -#define GLITCH_HIGH 2 -#define GLITCH_NONE 3 -#define GPIO_IN_PRESERVE_LOW_GLITCH (GLITCH_LOW << IN_GLITCH_SHIFT) -#define GPIO_IN_PRESERVE_HIGH_GLITCH (GLITCH_HIGH << IN_GLITCH_SHIFT) -#define GPIO_IN_REMOVE_GLITCH (GLITCH_NONE << IN_GLITCH_SHIFT) - -#define GPIO_TIMEBASE_61uS 0 -#define GPIO_TIMEBASE_183uS (1 << 4) -#define GPIO_TIMEBASE_15560uS (1 << 7) -#define GPIO_TIMEBASE_62440uS (GPIO_TIMEBASE_183uS | \ - GPIO_TIMEBASE_15560uS) -#define GPIO_IN_DEBOUNCE_DISABLED (0 | GPIO_TIMEBASE_61uS) -#define GPIO_IN_60uS (1 | GPIO_TIMEBASE_61uS) -#define GPIO_IN_120uS (2 | GPIO_TIMEBASE_61uS) -#define GPIO_IN_200uS (3 | GPIO_TIMEBASE_61uS) -#define GPIO_IN_500uS (8 | GPIO_TIMEBASE_61uS) -#define GPIO_IN_1mS (5 | GPIO_TIMEBASE_183uS) -#define GPIO_IN_2mS (11 | GPIO_TIMEBASE_183uS) -#define GPIO_IN_15mS (1 | GPIO_TIMEBASE_15560uS) -#define GPIO_IN_50mS (3 | GPIO_TIMEBASE_15560uS) -#define GPIO_IN_100mS (6 | GPIO_TIMEBASE_15560uS) -#define GPIO_IN_200mS (13 | GPIO_TIMEBASE_15560uS) -#define GPIO_IN_500mS (8 | GPIO_TIMEBASE_62440uS) - -#define GPIO_EVENT_INT_STATUS GPIO_INT_STATUS_EN -#define GPIO_EVENT_INT_DELIVER GPIO_INT_DELIVERY_EN -#define GPIO_EVENT_INT_STATUS_DELIVER (GPIO_INT_STATUS_EN | \ - GPIO_INT_DELIVERY_EN) -#define GPIO_WAKE_S0i3 (1 << 13) -#define GPIO_WAKE_S3 (1 << 14) -#define GPIO_WAKE_S4_S5 (1 << 15) -#define GPIO_WAKE_S0i3_S4_S5 (GPIO_WAKE_S0i3 | GPIO_WAKE_S4_S5) -#define GPIO_WAKE_S3_S4_S5 (GPIO_WAKE_S3 | GPIO_WAKE_S4_S5) - -/* - * Several macros are available to declare programming of GPIO pins, and if - * needed, more than 1 macro can be used for any pin. However, some macros - * will have no effect if combined. For example debounce only affects input - * or one of the interrupts. Some macros should not be combined, such as SMI - * and regular interrupt. The defined macros and their parameters are: - * PAD_NF Define native alternate function for the pin. - * pin the pin to be programmed - * function the native function - * pull pull up, pull down or no pull - * PAD_GPI The pin is a GPIO input - * pin the pin to be programmed - * pull pull up, pull down or no pull - * PAD_GPO The pin is a GPIO output - * pin the pin to be programmed - * direction high or low - * PAD_INT The pin is regular interrupt that works while booting - * pin the pin to be programmed - * pull pull up, pull down or no pull - * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES - * action STATUS, DELIVER, STATUS_DELIVER - * PAD_SCI The pin is a SCI source - * pin the pin to be programmed - * pull pull up, pull down or no pull - * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH - * PAD_SMI The pin is a SMI source - * pin the pin to be programmed - * pull pull up, pull down or no pull - * trigger LEVEL_LOW, LEVEL_HIGH - * PAD_WAKE The pin can wake, use after PAD_INT or PAD_SCI - * pin the pin to be programmed - * pull pull up, pull down or no pull - * trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES - * type S0i3, S3, S4_S5 or S4_S5 combinations (S0i3_S3 invalid) - * PAD_DEBOUNCE The input or interrupt will be debounced, invalid after - * PAD_NF - * pin the pin to be programmed - * debounce_type preserve low glitch, preserve high glitch, no glitch - * debounce_time the debounce time - */ - -/* Native function pad configuration */ -#define PAD_NF(pin, func, pull) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## func, \ - .control = GPIO_PULL ## _ ## pull, \ - .flags = 0 } -/* General purpose input pad configuration */ -#define PAD_GPI(pin, pull) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = GPIO_PULL ## _ ## pull, \ - .flags = 0 } -/* General purpose output pad configuration */ -#define PAD_GPO(pin, direction) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = GPIO_OUTPUT ## _OUT_ ## direction, \ - .flags = 0 } -/* Auxiliary macro for legacy interrupt and wake */ -#define PAD_AUX1(pull, trigger) (GPIO_PULL ## _ ## pull | \ - GPIO_INT ## _ ## trigger) -/* Legacy interrupt pad configuration */ -#define PAD_INT(pin, pull, trigger, action) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = (PAD_AUX1(pull, trigger) | \ - GPIO_EVENT_INT ## _ ## action), \ - .flags = GPIO_FLAG_INT } -/* Auxiliary macro for SCI and SMI */ -#define PAD_AUX2(trigger, flag) (GPIO_TRIGGER ## _ ## trigger | flag) -/* SCI pad configuration */ -#define PAD_SCI(pin, pull, trigger) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = GPIO_PULL ## _ ## pull, \ - .flags = PAD_AUX2(trigger, GPIO_FLAG_SCI) } -/* SMI pad configuration */ -#define PAD_SMI(pin, pull, trigger) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = GPIO_PULL ## _ ## pull, \ - .flags = PAD_AUX2(trigger, GPIO_FLAG_SMI) } -/* WAKE pad configuration */ -#define PAD_WAKE(pin, pull, trigger, type) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = (PAD_AUX1(pull, trigger) | \ - GPIO_WAKE ## _ ## type), \ - .flags = GPIO_FLAG_WAKE } -/* pin debounce configuration */ -#define PAD_DEBOUNCE(pin, type, time) \ - { .gpio = (pin), \ - .function = pin ## _IOMUX_ ## GPIOxx, \ - .control = (GPIO_IN ## _ ## type | GPIO_IN ## _ ## time), \ - .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 - * - * @param gpio_list_ptr = pointer to array of gpio configurations - * @param size = number of entries in array - * - * @return none - */ -void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size); - -/* Return the interrupt status and clear if set. */ -int gpio_interrupt_status(gpio_t gpio); - #endif /* __ACPI__ */ #endif /* __STONEYRIDGE_GPIO_H__ */ diff --git a/src/soc/amd/stoneyridge/include/soc/smi.h b/src/soc/amd/stoneyridge/include/soc/smi.h index d22b8dbdd5..000eed8554 100644 --- a/src/soc/amd/stoneyridge/include/soc/smi.h +++ b/src/soc/amd/stoneyridge/include/soc/smi.h @@ -233,6 +233,7 @@ void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level); void configure_scimap(const struct sci_source *sci); void disable_gevent_smi(uint8_t gevent); void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes); +void soc_route_sci(uint8_t event); #ifndef __SMM__ void enable_smi_generation(void); |