Hello Richard Spiegel, Martin Roth, Furquan Shaikh,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/32651
to review the following change.
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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.
Change-Id: I9cda00210a74de2bd1308ad43e2b867d24a67845 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h 16 files changed, 667 insertions(+), 577 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/32651/1
diff --git a/src/mainboard/amd/gardenia/bootblock/bootblock.c b/src/mainboard/amd/gardenia/bootblock/bootblock.c index 140bc07..2f4be03 100644 --- a/src/mainboard/amd/gardenia/bootblock/bootblock.c +++ b/src/mainboard/amd/gardenia/bootblock/bootblock.c @@ -23,5 +23,5 @@ size_t num_gpios; const struct soc_amd_gpio *gpios; gpios = early_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); } diff --git a/src/mainboard/amd/gardenia/mainboard.c b/src/mainboard/amd/gardenia/mainboard.c index b3f2285..3a4090c 100644 --- a/src/mainboard/amd/gardenia/mainboard.c +++ b/src/mainboard/amd/gardenia/mainboard.c @@ -82,7 +82,7 @@ size_t num_gpios; const struct soc_amd_gpio *gpios; gpios = gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); }
/************************************************* diff --git a/src/mainboard/google/kahlee/bootblock/bootblock.c b/src/mainboard/google/kahlee/bootblock/bootblock.c index 038cfe2..3be308e 100644 --- a/src/mainboard/google/kahlee/bootblock/bootblock.c +++ b/src/mainboard/google/kahlee/bootblock/bootblock.c @@ -29,7 +29,7 @@ mainboard_ec_init();
gpios = variant_early_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); }
void bootblock_mainboard_init(void) diff --git a/src/mainboard/google/kahlee/mainboard.c b/src/mainboard/google/kahlee/mainboard.c index cfd5637..f218f3f 100644 --- a/src/mainboard/google/kahlee/mainboard.c +++ b/src/mainboard/google/kahlee/mainboard.c @@ -27,6 +27,7 @@ #include <soc/nvs.h> #include <soc/pci_devs.h> #include <soc/southbridge.h> +#include <soc/smi.h> #include <amdblocks/acpimmio.h> #include <variant/ec.h> #include <variant/thermal.h> @@ -126,7 +127,7 @@ mainboard_ec_init();
gpios = variant_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios);
/* * Some platforms use SCI not generated by a GPIO pin (event above 23). diff --git a/src/mainboard/google/kahlee/romstage.c b/src/mainboard/google/kahlee/romstage.c index 32f8356..8bc766e 100644 --- a/src/mainboard/google/kahlee/romstage.c +++ b/src/mainboard/google/kahlee/romstage.c @@ -34,7 +34,7 @@ const struct soc_amd_gpio *gpios;
gpios = variant_romstage_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios);
variant_romstage_entry(s3_resume); } diff --git a/src/soc/amd/stoneyridge/acpi/gpio_lib.asl b/src/soc/amd/common/acpi/gpio_bank_lib.asl similarity index 100% rename from src/soc/amd/stoneyridge/acpi/gpio_lib.asl rename to 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 0000000..115aa2c --- /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 0000000..f1555b1 --- /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 0000000..0f3c2c7 --- /dev/null +++ b/src/soc/amd/common/block/gpio_banks/gpio.c @@ -0,0 +1,319 @@ +/* + * 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> + +extern const struct soc_amd_event gpio_event_table[]; + +static int get_gpio_gevent(uint8_t gpio) +{ + int i; + size_t size; + + size = soc_gpio_event_table_size(); + for (i = 0; i < size; 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) +{ + 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) +{ + return "\_SB.GPIO"; +} + +uint16_t gpio_acpi_pin(gpio_t gpio) +{ + return gpio; +} + +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; + uint8_t event; + 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 */ + + if (soc_override_event(gpio, mux, &event)) + route_sci(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; +} diff --git a/src/soc/amd/common/block/include/amdblocks/gpio.h b/src/soc/amd/common/block/include/amdblocks/gpio.h new file mode 100644 index 0000000..e6da5c5 --- /dev/null +++ b/src/soc/amd/common/block/include/amdblocks/gpio.h @@ -0,0 +1,306 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018 Silverback, ltd. + * + * 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_H__ +#define __AMDBLOCK_GPIO_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); +size_t soc_gpio_event_table_size(void); +int soc_override_event(uint8_t gpio, uint8_t mux, uint8_t *event); + +#endif /* __AMDBLOCK_GPIO_H__ */ diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index d4e1feb..5333f59 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -47,6 +47,7 @@ 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 4f11ea2..2cd9632 100644 --- a/src/soc/amd/stoneyridge/acpi.c +++ b/src/soc/amd/stoneyridge/acpi.c @@ -317,9 +317,9 @@
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_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 6fd838a..52c7ee6 100644 --- a/src/soc/amd/stoneyridge/acpi/soc.asl +++ b/src/soc/amd/stoneyridge/acpi/soc.asl @@ -28,4 +28,4 @@ #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 7c96805..0800a5a 100644 --- a/src/soc/amd/stoneyridge/gpio.c +++ b/src/soc/amd/stoneyridge/gpio.c @@ -15,16 +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 <amdblocks/acpimmio.h> +#include <stdint.h> +#include <amdblocks/gpio.h> #include <soc/gpio.h> -#include <assert.h> -#include "chip.h"
-static const struct soc_amd_event gpio_event_table[] = { +const struct soc_amd_event gpio_event_table[] = { { GPIO_1, GEVENT_19 }, { GPIO_2, GEVENT_8 }, { GPIO_3, GEVENT_2 }, @@ -51,288 +46,16 @@ { GPIO_69, GEVENT_17 }, };
-static int get_gpio_gevent(uint8_t gpio) +size_t soc_gpio_event_table_size(void) { - 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; + return ARRAY_SIZE(gpio_event_table); }
-static void mem_read_write32(uint32_t *address, uint32_t value, uint32_t mask) +int soc_override_event(uint8_t gpio, uint8_t mux, uint8_t *event) { - 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) -{ - 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) -{ - return "\_SB.GPIO"; -} - -uint16_t gpio_acpi_pin(gpio_t gpio) -{ - 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); + /* special case if pin 2 is assigned to wake */ + if ((gpio == 2) && !(mux & AMD_GPIO_MUX_MASK)) { + *event = GPIO_2_EVENT; return 1; }
diff --git a/src/soc/amd/stoneyridge/i2c.c b/src/soc/amd/stoneyridge/i2c.c index c3e5539..7f65a4f 100644 --- a/src/soc/amd/stoneyridge/i2c.c +++ b/src/soc/amd/stoneyridge/i2c.c @@ -203,7 +203,7 @@ /* 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 26d0336..7d15609 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.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 @@ #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 @@ #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 @@ #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__ */
Hello Richard Spiegel, build bot (Jenkins), Patrick Georgi, Martin Roth, Furquan Shaikh,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32651
to look at the new patch set (#2).
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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.
BUG=b:131682806
Change-Id: I9cda00210a74de2bd1308ad43e2b867d24a67845 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h 16 files changed, 667 insertions(+), 577 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/32651/2
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 2:
(2 comments)
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... File src/mainboard/google/kahlee/mainboard.c:
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... PS2, Line 30: <soc/smi.h> : Why is smi.h needed?
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... File src/soc/amd/stoneyridge/include/soc/gpio.h:
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... PS2, Line 75: Could you leave GPIO_BANK0_CONTROL, GPIO_BANK1_CONTROL and GPI2_BANK0_CONTROL in gpio.h (soc dependent)? In this way, a SOC with different MMIO offset could still use the same common block.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 2:
(2 comments)
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... File src/mainboard/google/kahlee/mainboard.c:
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... PS2, Line 30: <soc/smi.h> :
Why is smi. […]
Looks like that's left over from crud I used to have in here, but seems to build OK w/o the addition. I'll remove.
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... File src/soc/amd/stoneyridge/include/soc/gpio.h:
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... PS2, Line 75:
Could you leave GPIO_BANK0_CONTROL, GPIO_BANK1_CONTROL and GPI2_BANK0_CONTROL in gpio. […]
It won't have a different MMIO offset as the MMIO offsets have remained consistent over the last 10 years. There are two implementations of GPIOs The older one squeezed everything into the block at +100. The newer deprecated the use of +100 and implements 3 banks at +1500/1600/1700. Every device that falls within each of the two categories behaves like all the others in that category. This is also why I chose to name the newer feature "SOC_AMD_COMMON_BLOCK_BANKED_GPIOS". In the event we ever implemented the older one here, it wouldn't be banked.
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 2:
(1 comment)
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... File src/soc/amd/stoneyridge/include/soc/gpio.h:
https://review.coreboot.org/#/c/32651/2/src/soc/amd/stoneyridge/include/soc/... PS2, Line 75:
It won't have a different MMIO offset as the MMIO offsets have remained consistent over the last 10 […]
Got it.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 3:
(1 comment)
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... File src/mainboard/google/kahlee/mainboard.c:
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... PS2, Line 30: <soc/smi.h> :
...but seems to build OK w/o the addition.
Now I'm not sure what I was building when I made that statement. smi.h has the prototype for gpe_configure_sci() so it seems still seems necessary. The previous version of gpio.h contained #include <soc/smi.h>.
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 3: Code-Review+2
(1 comment)
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... File src/mainboard/google/kahlee/mainboard.c:
https://review.coreboot.org/#/c/32651/2/src/mainboard/google/kahlee/mainboar... PS2, Line 30: <soc/smi.h> :
...but seems to build OK w/o the addition. […]
I see, the original gpio.h included smi.h, the common gpio.h does not, thus it was needed to add it here. Also, smi.h never belonged to gpio.h, so you correctly removed it from gpio.h and added it here.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 3:
(2 comments)
https://review.coreboot.org/#/c/32651/3/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/3/src/soc/amd/common/block/include/amd... PS3, Line 303: size_t soc_gpio_event_table_size(void); : int soc_override_event(uint8_t gpio, uint8_t mux, uint8_t *event); It would be helpful to add comments indicating: 1. That these functions are expected to be implemented by the SoC. 2. What the function is supposed to do.
https://review.coreboot.org/#/c/32651/3/src/soc/amd/stoneyridge/gpio.c File src/soc/amd/stoneyridge/gpio.c:
https://review.coreboot.org/#/c/32651/3/src/soc/amd/stoneyridge/gpio.c@49 PS3, Line 49: soc_gpio_event_table_size Can this be instead renamed to soc_gpio_get_event_table_details which can fill in pointer to event table as well as the size and return back to common code? gpio_event_table[] then wouldn't have to be exposed directly outside the scope of this file.
Hello Richard Spiegel, build bot (Jenkins), Furquan Shaikh, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32651
to look at the new patch set (#4).
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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.
BUG=b:131682806
Change-Id: I9cda00210a74de2bd1308ad43e2b867d24a67845 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h 16 files changed, 674 insertions(+), 576 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/32651/4
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 4:
(2 comments)
https://review.coreboot.org/#/c/32651/3/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/3/src/soc/amd/common/block/include/amd... PS3, Line 303: size_t soc_gpio_event_table_size(void); : int soc_override_event(uint8_t gpio, uint8_t mux, uint8_t *event);
It would be helpful to add comments indicating: […]
Done
https://review.coreboot.org/#/c/32651/3/src/soc/amd/stoneyridge/gpio.c File src/soc/amd/stoneyridge/gpio.c:
https://review.coreboot.org/#/c/32651/3/src/soc/amd/stoneyridge/gpio.c@49 PS3, Line 49: soc_gpio_event_table_size
Can this be instead renamed to soc_gpio_get_event_table_details which can fill in pointer to event t […]
Done with different name.
Furquan Shaikh has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 4: Code-Review+1
(4 comments)
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... File src/soc/amd/common/block/gpio_banks/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 33: soc_get_gpio_event_table(&table, &items); If you put this call in program_gpios() before the for(...) loop, you can avoid making the callback for every index and instead just pass in table and items to get_gpio_event(gpio, table, items)
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 53: configure_gevent_smi Should this be a weak function or something that fails to compile if not provided by the SoC?
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 241: route_sci(event); Is this always going to be true for all SoCs using this common code? Or should this just be a soc_force_event() or soc_override_event() that the SoC implementation can use to route the event as required i.e. make the call to route_sci() within the SoC implementation.
https://review.coreboot.org/#/c/32651/4/src/soc/amd/stoneyridge/gpio.c File src/soc/amd/stoneyridge/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/stoneyridge/gpio.c@49 PS4, Line 49: int size_t?
Hello Richard Spiegel, build bot (Jenkins), Furquan Shaikh, Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32651
to look at the new patch set (#5).
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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.
BUG=b:131682806
Change-Id: I9cda00210a74de2bd1308ad43e2b867d24a67845 Signed-off-by: Marshall Dawson marshalldawson3rd@gmail.com --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio.h A src/soc/amd/common/block/include/amdblocks/gpio_banks.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h M src/soc/amd/stoneyridge/include/soc/smi.h 18 files changed, 971 insertions(+), 575 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/32651/5
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 304: void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items); line over 80 characters
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio_banks.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 304: void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items); line over 80 characters
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(5 comments)
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... File src/soc/amd/common/block/gpio_banks/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 33: soc_get_gpio_event_table(&table, &items);
If you put this call in program_gpios() before the for(... […]
Done
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 53: configure_gevent_smi
Should this be a weak function or something that fails to compile if not provided by the SoC?
I don't recall my exact line of thinking now, seems reasonable to remove this.
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 241: route_sci(event);
Is this always going to be true for all SoCs using this common code?
I decided to just call it a hook rather than predict what may come in the future. Also, it occurred to me that route_sci writes one of the registers in SMI's AcpiMmio space and doesn't really belong in this file.
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 304: void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items);
line over 80 characters
No longer an error, right? Or at this point is it easier to shorten the line?
https://review.coreboot.org/#/c/32651/4/src/soc/amd/stoneyridge/gpio.c File src/soc/amd/stoneyridge/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/stoneyridge/gpio.c@49 PS4, Line 49: int
size_t?
Done
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 304: void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items);
No longer an error, right? Or at this point is it easier to shorten the line?
No, this is fine at this point.
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 2: * This file is part of the coreboot project. Is this file still needed? It's the same as gpio_banks.h
Richard Spiegel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(1 comment)
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... File src/soc/amd/common/block/gpio_banks/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 53: configure_gevent_smi
I don't recall my exact line of thinking now, seems reasonable to remove this.
This is part of original code, for runtime warning if SMI is disabled. If you remove it and SMI is disabled, it'll not build.
Marshall Dawson has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 5:
(2 comments)
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... File src/soc/amd/common/block/gpio_banks/gpio.c:
https://review.coreboot.org/#/c/32651/4/src/soc/amd/common/block/gpio_banks/... PS4, Line 53: configure_gevent_smi
This is part of original code, for runtime warning if SMI is disabled. […]
Yes, that's right Richard. soc//stoneyridge is still a lot like the older cpu/nb/sb implementations that can be build with or without HAVE_SMI_HANDLER selected. However it, like newer Intel devices, relies on having SMI to do its CPU setup.
Given that we won't implement another device the old way, I think this is the right time to take it out. I'll add a note to the commit message. Removing the stoneyridge/Makefile.inc dependencies on CONFIG_HAVE_SMI_HANDLER can go into a separate patch.
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio.h:
https://review.coreboot.org/#/c/32651/5/src/soc/amd/common/block/include/amd... PS5, Line 2: * This file is part of the coreboot project.
Is this file still needed? It's the same as gpio_banks. […]
No, not supposed to be here. Some combination of git mv and fixing up went wrong. Will update it right now.
Hello Richard Spiegel, build bot (Jenkins), Martin Roth, Furquan Shaikh, Patrick Georgi,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/32651
to look at the new patch set (#6).
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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 --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio_banks.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h M src/soc/amd/stoneyridge/include/soc/smi.h 17 files changed, 663 insertions(+), 575 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/51/32651/6
build bot (Jenkins) has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 6:
(1 comment)
https://review.coreboot.org/#/c/32651/6/src/soc/amd/common/block/include/amd... File src/soc/amd/common/block/include/amdblocks/gpio_banks.h:
https://review.coreboot.org/#/c/32651/6/src/soc/amd/common/block/include/amd... PS6, Line 304: void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items); line over 80 characters
Martin Roth has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
Patch Set 6: Code-Review+2
Martin Roth has submitted this change and it was merged. ( https://review.coreboot.org/c/coreboot/+/32651 )
Change subject: soc/amd/stoneyridge: Move GPIO support to common ......................................................................
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 --- M src/mainboard/amd/gardenia/bootblock/bootblock.c M src/mainboard/amd/gardenia/mainboard.c M src/mainboard/google/kahlee/bootblock/bootblock.c M src/mainboard/google/kahlee/mainboard.c M src/mainboard/google/kahlee/romstage.c R src/soc/amd/common/acpi/gpio_bank_lib.asl A src/soc/amd/common/block/gpio_banks/Kconfig A src/soc/amd/common/block/gpio_banks/Makefile.inc A src/soc/amd/common/block/gpio_banks/gpio.c A src/soc/amd/common/block/include/amdblocks/gpio_banks.h M src/soc/amd/stoneyridge/Kconfig M src/soc/amd/stoneyridge/acpi.c M src/soc/amd/stoneyridge/acpi/soc.asl M src/soc/amd/stoneyridge/gpio.c M src/soc/amd/stoneyridge/i2c.c M src/soc/amd/stoneyridge/include/soc/gpio.h M src/soc/amd/stoneyridge/include/soc/smi.h 17 files changed, 663 insertions(+), 575 deletions(-)
Approvals: build bot (Jenkins): Verified Martin Roth: Looks good to me, approved
diff --git a/src/mainboard/amd/gardenia/bootblock/bootblock.c b/src/mainboard/amd/gardenia/bootblock/bootblock.c index 140bc07..2f4be03 100644 --- a/src/mainboard/amd/gardenia/bootblock/bootblock.c +++ b/src/mainboard/amd/gardenia/bootblock/bootblock.c @@ -23,5 +23,5 @@ size_t num_gpios; const struct soc_amd_gpio *gpios; gpios = early_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); } diff --git a/src/mainboard/amd/gardenia/mainboard.c b/src/mainboard/amd/gardenia/mainboard.c index b3f2285..3a4090c 100644 --- a/src/mainboard/amd/gardenia/mainboard.c +++ b/src/mainboard/amd/gardenia/mainboard.c @@ -82,7 +82,7 @@ size_t num_gpios; const struct soc_amd_gpio *gpios; gpios = gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); }
/************************************************* diff --git a/src/mainboard/google/kahlee/bootblock/bootblock.c b/src/mainboard/google/kahlee/bootblock/bootblock.c index 038cfe2..3be308e 100644 --- a/src/mainboard/google/kahlee/bootblock/bootblock.c +++ b/src/mainboard/google/kahlee/bootblock/bootblock.c @@ -29,7 +29,7 @@ mainboard_ec_init();
gpios = variant_early_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios); }
void bootblock_mainboard_init(void) diff --git a/src/mainboard/google/kahlee/mainboard.c b/src/mainboard/google/kahlee/mainboard.c index cfd5637..f218f3f 100644 --- a/src/mainboard/google/kahlee/mainboard.c +++ b/src/mainboard/google/kahlee/mainboard.c @@ -27,6 +27,7 @@ #include <soc/nvs.h> #include <soc/pci_devs.h> #include <soc/southbridge.h> +#include <soc/smi.h> #include <amdblocks/acpimmio.h> #include <variant/ec.h> #include <variant/thermal.h> @@ -126,7 +127,7 @@ mainboard_ec_init();
gpios = variant_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios);
/* * Some platforms use SCI not generated by a GPIO pin (event above 23). diff --git a/src/mainboard/google/kahlee/romstage.c b/src/mainboard/google/kahlee/romstage.c index 32f8356..8bc766e 100644 --- a/src/mainboard/google/kahlee/romstage.c +++ b/src/mainboard/google/kahlee/romstage.c @@ -34,7 +34,7 @@ const struct soc_amd_gpio *gpios;
gpios = variant_romstage_gpio_table(&num_gpios); - sb_program_gpios(gpios, num_gpios); + program_gpios(gpios, num_gpios);
variant_romstage_entry(s3_resume); } diff --git a/src/soc/amd/stoneyridge/acpi/gpio_lib.asl b/src/soc/amd/common/acpi/gpio_bank_lib.asl similarity index 100% rename from src/soc/amd/stoneyridge/acpi/gpio_lib.asl rename to 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 0000000..115aa2c --- /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 0000000..f1555b1 --- /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 0000000..17e3de0 --- /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 0000000..da84134 --- /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 d4e1feb..5333f59 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -47,6 +47,7 @@ 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 4f11ea2..2cd9632 100644 --- a/src/soc/amd/stoneyridge/acpi.c +++ b/src/soc/amd/stoneyridge/acpi.c @@ -317,9 +317,9 @@
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_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 6fd838a..52c7ee6 100644 --- a/src/soc/amd/stoneyridge/acpi/soc.asl +++ b/src/soc/amd/stoneyridge/acpi/soc.asl @@ -28,4 +28,4 @@ #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 7c96805..f63a0d9 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 @@ { 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) +void soc_get_gpio_event_table(const struct soc_amd_event **table, size_t *items) { - 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; - } + *table = gpio_event_table; + *items = ARRAY_SIZE(gpio_event_table); }
-uintptr_t gpio_get_address(gpio_t gpio_num) +void soc_gpio_hook(uint8_t gpio, uint8_t mux) { - 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; -} - -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 c3e5539..7f65a4f 100644 --- a/src/soc/amd/stoneyridge/i2c.c +++ b/src/soc/amd/stoneyridge/i2c.c @@ -203,7 +203,7 @@ /* 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 26d0336..d8774f0 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 @@ #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 @@ #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 @@ #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 d22b8db..000eed8 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_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);