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:
parent
eb5b0d05a7
commit
251d305e73
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue