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>
This commit is contained in:
Marshall Dawson 2019-05-02 17:27:57 -06:00 committed by Martin Roth
parent eb5b0d05a7
commit 251d305e73
17 changed files with 663 additions and 575 deletions

View File

@ -23,5 +23,5 @@ void bootblock_mainboard_early_init(void)
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);
}

View File

@ -82,7 +82,7 @@ static void mainboard_init(void *chip_info)
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);
}
/*************************************************

View File

@ -29,7 +29,7 @@ void bootblock_mainboard_early_init(void)
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)

View File

@ -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 @@ static void mainboard_init(void *chip_info)
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).

View File

@ -34,7 +34,7 @@ void mainboard_romstage_entry(int s3_resume)
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);
}

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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__ */

View File

@ -47,6 +47,7 @@ config CPU_SPECIFIC_OPTIONS
select SOC_AMD_COMMON
select SOC_AMD_COMMON_BLOCK
select SOC_AMD_COMMON_BLOCK_ACPIMMIO
select SOC_AMD_COMMON_BLOCK_BANKED_GPIOS
select SOC_AMD_COMMON_BLOCK_PCI
select SOC_AMD_COMMON_BLOCK_PI
select SOC_AMD_COMMON_BLOCK_PSP

View File

@ -317,9 +317,9 @@ static void acpigen_soc_get_gpio_in_local5(uintptr_t addr)
static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask)
{
if (gpio_num >= GPIO_TOTAL_PINS) {
if (gpio_num >= SOC_GPIO_TOTAL_PINS) {
printk(BIOS_WARNING, "Warning: Pin %d should be smaller than"
" %d\n", gpio_num, GPIO_TOTAL_PINS);
" %d\n", gpio_num, SOC_GPIO_TOTAL_PINS);
return -1;
}
uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num);
@ -347,9 +347,9 @@ static int acpigen_soc_get_gpio_val(unsigned int gpio_num, uint32_t mask)
static int acpigen_soc_set_gpio_val(unsigned int gpio_num, uint32_t val)
{
if (gpio_num >= GPIO_TOTAL_PINS) {
if (gpio_num >= SOC_GPIO_TOTAL_PINS) {
printk(BIOS_WARNING, "Warning: Pin %d should be smaller than"
" %d\n", gpio_num, GPIO_TOTAL_PINS);
" %d\n", gpio_num, SOC_GPIO_TOTAL_PINS);
return -1;
}
uintptr_t addr = (uintptr_t) gpio_get_address(gpio_num);

View File

@ -28,4 +28,4 @@ Device(PCI0) {
#include "sb_fch.asl"
/* Add GPIO library */
#include <gpio_lib.asl>
#include <soc/amd/common/acpi/gpio_bank_lib.asl>

View File

@ -15,14 +15,11 @@
* GNU General Public License for more details.
*/
#include <device/mmio.h>
#include <device/device.h>
#include <console/console.h>
#include <gpio.h>
#include <stdint.h>
#include <amdblocks/gpio_banks.h>
#include <amdblocks/acpimmio.h>
#include <soc/gpio.h>
#include <assert.h>
#include "chip.h"
#include <soc/smi.h>
static const struct soc_amd_event gpio_event_table[] = {
{ GPIO_1, GEVENT_19 },
@ -51,290 +48,20 @@ static const struct soc_amd_event gpio_event_table[] = {
{ GPIO_69, GEVENT_17 },
};
static int get_gpio_gevent(uint8_t gpio)
{
int i;
for (i = 0; i < ARRAY_SIZE(gpio_event_table); i++) {
if (gpio_event_table[i].gpio == gpio)
return (int)gpio_event_table[i].event;
}
return -1;
}
static void mem_read_write32(uint32_t *address, uint32_t value, uint32_t mask)
{
uint32_t reg32;
value &= mask;
reg32 = read32(address);
reg32 &= ~mask;
reg32 |= value;
write32(address, reg32);
}
__weak void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level)
{
printk(BIOS_WARNING, "Warning: SMI disabled!\n");
}
static void program_smi(uint32_t flag, int gevent_num)
{
uint32_t trigger;
trigger = flag & FLAGS_TRIGGER_MASK;
/*
* Only level trigger is allowed for SMI. Trigger values are 0
* through 3, with 0-1 being level trigger and 2-3 being edge
* trigger. GPIO_TRIGGER_EDGE_LOW is 2, so trigger has to be
* less than GPIO_TRIGGER_EDGE_LOW.
*/
assert(trigger < GPIO_TRIGGER_EDGE_LOW);
if (trigger == GPIO_TRIGGER_LEVEL_HIGH)
configure_gevent_smi(gevent_num, SMI_MODE_SMI,
SMI_SCI_LVL_HIGH);
if (trigger == GPIO_TRIGGER_LEVEL_LOW)
configure_gevent_smi(gevent_num, SMI_MODE_SMI,
SMI_SCI_LVL_LOW);
}
static void route_sci(uint8_t event)
void soc_route_sci(uint8_t event)
{
smi_write8(SMI_SCI_MAP(event), event);
}
static void get_sci_config_bits(uint32_t flag, uint32_t *edge, uint32_t *level)
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);
}

View File

@ -203,7 +203,7 @@ void sb_reset_i2c_slaves(void)
/* Save and reprogram I2C SCL pins */
for (i = 0; i < saved_pins_count; i++)
save_i2c_pin_registers(i2c_2_gpi[i].gpio, &save_table[i]);
sb_program_gpios(i2c_2_gpi, saved_pins_count);
program_gpios(i2c_2_gpi, saved_pins_count);
/*
* Toggle SCL back and forth 9 times under 100KHz. A single read is

View File

@ -21,59 +21,13 @@
#ifndef __ACPI__
#include <soc/iomap.h>
#include <soc/smi.h>
#include <types.h>
#include <amdblocks/gpio_banks.h>
struct soc_amd_gpio {
uint8_t gpio;
uint8_t function;
uint32_t control;
uint32_t flags;
};
/* The following sections describe only the GPIOs defined for this SOC */
struct soc_amd_event {
uint8_t gpio;
uint8_t event;
};
#define SOC_GPIO_TOTAL_PINS 149
#define GPIO_MASTER_SWITCH 0xFC
#define GPIO_MASK_STS_EN BIT(28)
#define GPIO_INTERRUPT_EN BIT(30)
#define GPIO_TOTAL_PINS 149
#define GPIO_PIN_IN (1 << 0) /* for byte access */
#define GPIO_PIN_OUT (1 << 6) /* for byte access */
#define GPIO_EDGE_TRIG (0 << 8)
#define GPIO_LEVEL_TRIG (1 << 8)
#define GPIO_TRIGGER_MASK (1 << 8)
#define GPIO_ACTIVE_HIGH (0 << 9)
#define GPIO_ACTIVE_LOW (1 << 9)
#define GPIO_ACTIVE_BOTH (2 << 9)
#define GPIO_ACTIVE_MASK (3 << 9)
#define GPIO_INT_STATUS_EN (1 << 11)
#define GPIO_INT_DELIVERY_EN (1 << 12)
#define GPIO_INTERRUPT_MASK (3 << 11)
#define GPIO_S0I3_WAKE_EN (1 << 13)
#define GPIO_S3_WAKE_EN (1 << 14)
#define GPIO_S4_S5_WAKE_EN (1 << 15)
#define GPIO_PIN_STS (1 << 16)
#define GPIO_PULLUP_ENABLE (1 << 20)
#define GPIO_PULLDOWN_ENABLE (1 << 21)
#define GPIO_OUTPUT_SHIFT 22
#define GPIO_OUTPUT_MASK (1 << GPIO_OUTPUT_SHIFT)
#define GPIO_OUTPUT_VALUE (1 << GPIO_OUTPUT_SHIFT)
#define GPIO_OUTPUT_ENABLE (1 << 23)
#define GPIO_INT_STATUS (1 << 28)
#define GPIO_WAKE_STATUS (1 << 29)
/* GPIO_0 - GPIO_62 */
#define GPIO_BANK0_CONTROL(gpio) \
(AMD_SB_ACPI_MMIO_ADDR + 0x1500 + ((gpio) * 4))
/* Bank 0: GPIO_0 - GPIO_62 */
#define GPIO_0 0
#define GPIO_1 1
#define GPIO_2 2
@ -105,9 +59,7 @@ struct soc_amd_event {
#define GPIO_40 40
#define GPIO_42 42
/* GPIO_64 - GPIO_127 */
#define GPIO_BANK1_CONTROL(gpio) \
(AMD_SB_ACPI_MMIO_ADDR + 0x1600 + (((gpio) - 64) * 4))
/* Bank 1: GPIO_64 - GPIO_127 */
#define GPIO_64 64
#define GPIO_65 65
#define GPIO_66 66
@ -150,10 +102,7 @@ struct soc_amd_event {
#define GPIO_122 122
#define GPIO_126 126
/* GPIO_128 - GPIO_183 */
#define GPIO_BANK2_CONTROL(gpio) \
(AMD_SB_ACPI_MMIO_ADDR + 0x1700 + (((gpio) - 128) * 4))
/* GPIO_128 Reserved */
/* Bank 2: GPIO_128 - GPIO_183 */
#define GPIO_129 129
#define GPIO_130 130
#define GPIO_131 131
@ -353,230 +302,7 @@ struct soc_amd_event {
#define GPIO_148_IOMUX_I2C1_SDA 0
#define GPIO_148_IOMUX_GPIOxx 1
enum {
GEVENT_0,
GEVENT_1,
GEVENT_2,
GEVENT_3,
GEVENT_4,
GEVENT_5,
GEVENT_6,
GEVENT_7,
GEVENT_8,
GEVENT_9,
GEVENT_10,
GEVENT_11,
GEVENT_12,
GEVENT_13,
GEVENT_14,
GEVENT_15,
GEVENT_16,
GEVENT_17,
GEVENT_18,
GEVENT_19,
GEVENT_20,
GEVENT_21,
GEVENT_22,
GEVENT_23,
};
#define GPIO_2_EVENT GEVENT_8
#define GPIO_OUTPUT_OUT_HIGH (GPIO_OUTPUT_ENABLE | GPIO_OUTPUT_VALUE)
#define GPIO_OUTPUT_OUT_LOW GPIO_OUTPUT_ENABLE
#define GPIO_PULL_PULL_UP GPIO_PULLUP_ENABLE
#define GPIO_PULL_PULL_DOWN GPIO_PULLDOWN_ENABLE
#define GPIO_PULL_PULL_NONE 0
#define AMD_GPIO_CONTROL_MASK 0x00f4ff00
#define AMD_GPIO_MUX_MASK 0x03
/* Definitions for PAD_INT. */
#define GPIO_INT_EDGE_HIGH (GPIO_ACTIVE_HIGH | GPIO_EDGE_TRIG)
#define GPIO_INT_EDGE_LOW (GPIO_ACTIVE_LOW | GPIO_EDGE_TRIG)
#define GPIO_INT_BOTH_EDGES (GPIO_ACTIVE_BOTH | GPIO_EDGE_TRIG)
#define GPIO_INT_LEVEL_HIGH (GPIO_ACTIVE_HIGH | GPIO_LEVEL_TRIG)
#define GPIO_INT_LEVEL_LOW (GPIO_ACTIVE_LOW | GPIO_LEVEL_TRIG)
enum {
GPIO_TRIGGER_LEVEL_LOW,
GPIO_TRIGGER_LEVEL_HIGH,
GPIO_TRIGGER_EDGE_LOW,
GPIO_TRIGGER_EDGE_HIGH,
};
#define GPIO_TRIGGER_INVALID -1
#define SCI_TRIGGER_EDGE 0
#define SCI_TRIGGER_LEVEL 1
#define GPIO_SPECIAL_FLAG (1 << 31)
#define GPIO_DEBOUNCE_FLAG (1 << 30)
#define GPIO_WAKE_FLAG (1 << 29)
#define GPIO_INT_FLAG (1 << 28)
#define GPIO_SMI_FLAG (1 << 27)
#define GPIO_SCI_FLAG (1 << 26)
#define GPIO_FLAG_DEBOUNCE (GPIO_SPECIAL_FLAG | GPIO_DEBOUNCE_FLAG)
#define GPIO_FLAG_WAKE (GPIO_SPECIAL_FLAG | GPIO_WAKE_FLAG)
#define GPIO_FLAG_INT (GPIO_SPECIAL_FLAG | GPIO_INT_FLAG)
#define GPIO_FLAG_SCI (GPIO_SPECIAL_FLAG | GPIO_SCI_FLAG)
#define GPIO_FLAG_SMI (GPIO_SPECIAL_FLAG | GPIO_SMI_FLAG)
#define FLAGS_TRIGGER_MASK 0x00000003
#define GPIO_SPECIAL_MASK 0x7c000000
#define GPIO_DEBOUNCE_MASK 0x000000ff
#define INT_TRIGGER_MASK 0x00000700
#define INT_WAKE_MASK 0x0000e700
#define INT_SCI_SMI_MASK 0x00f40000
#define IN_GLITCH_SHIFT 5
#define GLITCH_LOW 1
#define GLITCH_HIGH 2
#define GLITCH_NONE 3
#define GPIO_IN_PRESERVE_LOW_GLITCH (GLITCH_LOW << IN_GLITCH_SHIFT)
#define GPIO_IN_PRESERVE_HIGH_GLITCH (GLITCH_HIGH << IN_GLITCH_SHIFT)
#define GPIO_IN_REMOVE_GLITCH (GLITCH_NONE << IN_GLITCH_SHIFT)
#define GPIO_TIMEBASE_61uS 0
#define GPIO_TIMEBASE_183uS (1 << 4)
#define GPIO_TIMEBASE_15560uS (1 << 7)
#define GPIO_TIMEBASE_62440uS (GPIO_TIMEBASE_183uS | \
GPIO_TIMEBASE_15560uS)
#define GPIO_IN_DEBOUNCE_DISABLED (0 | GPIO_TIMEBASE_61uS)
#define GPIO_IN_60uS (1 | GPIO_TIMEBASE_61uS)
#define GPIO_IN_120uS (2 | GPIO_TIMEBASE_61uS)
#define GPIO_IN_200uS (3 | GPIO_TIMEBASE_61uS)
#define GPIO_IN_500uS (8 | GPIO_TIMEBASE_61uS)
#define GPIO_IN_1mS (5 | GPIO_TIMEBASE_183uS)
#define GPIO_IN_2mS (11 | GPIO_TIMEBASE_183uS)
#define GPIO_IN_15mS (1 | GPIO_TIMEBASE_15560uS)
#define GPIO_IN_50mS (3 | GPIO_TIMEBASE_15560uS)
#define GPIO_IN_100mS (6 | GPIO_TIMEBASE_15560uS)
#define GPIO_IN_200mS (13 | GPIO_TIMEBASE_15560uS)
#define GPIO_IN_500mS (8 | GPIO_TIMEBASE_62440uS)
#define GPIO_EVENT_INT_STATUS GPIO_INT_STATUS_EN
#define GPIO_EVENT_INT_DELIVER GPIO_INT_DELIVERY_EN
#define GPIO_EVENT_INT_STATUS_DELIVER (GPIO_INT_STATUS_EN | \
GPIO_INT_DELIVERY_EN)
#define GPIO_WAKE_S0i3 (1 << 13)
#define GPIO_WAKE_S3 (1 << 14)
#define GPIO_WAKE_S4_S5 (1 << 15)
#define GPIO_WAKE_S0i3_S4_S5 (GPIO_WAKE_S0i3 | GPIO_WAKE_S4_S5)
#define GPIO_WAKE_S3_S4_S5 (GPIO_WAKE_S3 | GPIO_WAKE_S4_S5)
/*
* Several macros are available to declare programming of GPIO pins, and if
* needed, more than 1 macro can be used for any pin. However, some macros
* will have no effect if combined. For example debounce only affects input
* or one of the interrupts. Some macros should not be combined, such as SMI
* and regular interrupt. The defined macros and their parameters are:
* PAD_NF Define native alternate function for the pin.
* pin the pin to be programmed
* function the native function
* pull pull up, pull down or no pull
* PAD_GPI The pin is a GPIO input
* pin the pin to be programmed
* pull pull up, pull down or no pull
* PAD_GPO The pin is a GPIO output
* pin the pin to be programmed
* direction high or low
* PAD_INT The pin is regular interrupt that works while booting
* pin the pin to be programmed
* pull pull up, pull down or no pull
* trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES
* action STATUS, DELIVER, STATUS_DELIVER
* PAD_SCI The pin is a SCI source
* pin the pin to be programmed
* pull pull up, pull down or no pull
* trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH
* PAD_SMI The pin is a SMI source
* pin the pin to be programmed
* pull pull up, pull down or no pull
* trigger LEVEL_LOW, LEVEL_HIGH
* PAD_WAKE The pin can wake, use after PAD_INT or PAD_SCI
* pin the pin to be programmed
* pull pull up, pull down or no pull
* trigger LEVEL_LOW, LEVEL_HIGH, EDGE_LOW, EDGE_HIGH, BOTH_EDGES
* type S0i3, S3, S4_S5 or S4_S5 combinations (S0i3_S3 invalid)
* PAD_DEBOUNCE The input or interrupt will be debounced, invalid after
* PAD_NF
* pin the pin to be programmed
* debounce_type preserve low glitch, preserve high glitch, no glitch
* debounce_time the debounce time
*/
/* Native function pad configuration */
#define PAD_NF(pin, func, pull) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## func, \
.control = GPIO_PULL ## _ ## pull, \
.flags = 0 }
/* General purpose input pad configuration */
#define PAD_GPI(pin, pull) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = GPIO_PULL ## _ ## pull, \
.flags = 0 }
/* General purpose output pad configuration */
#define PAD_GPO(pin, direction) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = GPIO_OUTPUT ## _OUT_ ## direction, \
.flags = 0 }
/* Auxiliary macro for legacy interrupt and wake */
#define PAD_AUX1(pull, trigger) (GPIO_PULL ## _ ## pull | \
GPIO_INT ## _ ## trigger)
/* Legacy interrupt pad configuration */
#define PAD_INT(pin, pull, trigger, action) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = (PAD_AUX1(pull, trigger) | \
GPIO_EVENT_INT ## _ ## action), \
.flags = GPIO_FLAG_INT }
/* Auxiliary macro for SCI and SMI */
#define PAD_AUX2(trigger, flag) (GPIO_TRIGGER ## _ ## trigger | flag)
/* SCI pad configuration */
#define PAD_SCI(pin, pull, trigger) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = GPIO_PULL ## _ ## pull, \
.flags = PAD_AUX2(trigger, GPIO_FLAG_SCI) }
/* SMI pad configuration */
#define PAD_SMI(pin, pull, trigger) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = GPIO_PULL ## _ ## pull, \
.flags = PAD_AUX2(trigger, GPIO_FLAG_SMI) }
/* WAKE pad configuration */
#define PAD_WAKE(pin, pull, trigger, type) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = (PAD_AUX1(pull, trigger) | \
GPIO_WAKE ## _ ## type), \
.flags = GPIO_FLAG_WAKE }
/* pin debounce configuration */
#define PAD_DEBOUNCE(pin, type, time) \
{ .gpio = (pin), \
.function = pin ## _IOMUX_ ## GPIOxx, \
.control = (GPIO_IN ## _ ## type | GPIO_IN ## _ ## time), \
.flags = GPIO_FLAG_DEBOUNCE }
typedef uint32_t gpio_t;
/* Get the address of the control register of a particular pin */
uintptr_t gpio_get_address(gpio_t gpio_num);
/**
* @brief program a particular set of GPIO
*
* @param gpio_list_ptr = pointer to array of gpio configurations
* @param size = number of entries in array
*
* @return none
*/
void sb_program_gpios(const struct soc_amd_gpio *gpio_list_ptr, size_t size);
/* Return the interrupt status and clear if set. */
int gpio_interrupt_status(gpio_t gpio);
#endif /* __ACPI__ */
#endif /* __STONEYRIDGE_GPIO_H__ */

View File

@ -233,6 +233,7 @@ void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level);
void configure_scimap(const struct sci_source *sci);
void disable_gevent_smi(uint8_t gevent);
void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes);
void soc_route_sci(uint8_t event);
#ifndef __SMM__
void enable_smi_generation(void);