From 4bf11ce2b5de81ec0bd6799f4830a48c7376c122 Mon Sep 17 00:00:00 2001 From: Werner Zeh Date: Mon, 16 Oct 2017 08:37:28 +0200 Subject: soc/fsp_broadwell_de: Add support for GPIO handling Add functionality to initialize, set and read back GPIOs on FSP based Broadwell-DE implementation. Change-Id: Ibbd86e2142bbf5772eb4a91ebb9166c31d52476e Signed-off-by: Werner Zeh Reviewed-on: https://review.coreboot.org/22034 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/soc/intel/fsp_broadwell_de/Makefile.inc | 3 + src/soc/intel/fsp_broadwell_de/gpio.c | 109 +++++++++++++++++ src/soc/intel/fsp_broadwell_de/include/soc/gpio.h | 130 +++++++++++++++++++++ src/soc/intel/fsp_broadwell_de/include/soc/iomap.h | 5 + src/soc/intel/fsp_broadwell_de/include/soc/lpc.h | 3 + src/soc/intel/fsp_broadwell_de/romstage/romstage.c | 13 +++ src/soc/intel/fsp_broadwell_de/southcluster.c | 12 ++ 7 files changed, 275 insertions(+) create mode 100644 src/soc/intel/fsp_broadwell_de/gpio.c create mode 100644 src/soc/intel/fsp_broadwell_de/include/soc/gpio.h (limited to 'src/soc/intel') diff --git a/src/soc/intel/fsp_broadwell_de/Makefile.inc b/src/soc/intel/fsp_broadwell_de/Makefile.inc index 38cc4411db..fc6cdd3d42 100644 --- a/src/soc/intel/fsp_broadwell_de/Makefile.inc +++ b/src/soc/intel/fsp_broadwell_de/Makefile.inc @@ -11,6 +11,8 @@ subdirs-y += ../../../cpu/x86/cache subdirs-y += ../../../lib/fsp subdirs-y += fsp +romstage-y += gpio.c + ramstage-y += spi.c ramstage-y += cpu.c ramstage-y += chip.c @@ -27,6 +29,7 @@ ramstage-y += smbus_common.c ramstage-y += smbus.c romstage-y += tsc_freq.c ramstage-y += smi.c +ramstage-y += gpio.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c ramstage-$(CONFIG_HAVE_SMI_HANDLER) += pmutil.c smm-$(CONFIG_HAVE_SMI_HANDLER) += pmutil.c diff --git a/src/soc/intel/fsp_broadwell_de/gpio.c b/src/soc/intel/fsp_broadwell_de/gpio.c new file mode 100644 index 0000000000..41100e928c --- /dev/null +++ b/src/soc/intel/fsp_broadwell_de/gpio.c @@ -0,0 +1,109 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Siemens AG + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* Use a wrapper for register addresses for different banks. */ +const static struct gpio_config_regs regs[GPIO_NUM_BANKS] = { + [0] = { .use_sel = GPIO_1_USE_SEL, .io_sel = GPIO_1_IO_SEL, + .level = GPIO_1_LVL, .nmi_en = GPIO_1_NMI_EN, + .blink_en = GPIO_1_BLINK, .invert_input = GPIO_1_INVERT }, + [1] = { .use_sel = GPIO_2_USE_SEL, .io_sel = GPIO_2_IO_SEL, + .level = GPIO_2_LVL, .nmi_en = GPIO_2_NMI_EN, + .blink_en = REG_INVALID, .invert_input = REG_INVALID }, + [2] = { .use_sel = GPIO_3_USE_SEL, .io_sel = GPIO_3_IO_SEL, + .level = GPIO_3_LVL, .nmi_en = GPIO_3_NMI_EN, + .blink_en = REG_INVALID, .invert_input = REG_INVALID }, + }; + +#define SETUP_GPIO_REG(reg, bit, bank) { uint32_t val; \ + val = inl(GPIO_BASE_ADDRESS + regs[(bank)].reg); \ + val &= ~(1 << (bit)); \ + val |= ((pin->reg) << (bit)); \ + outl(val, GPIO_BASE_ADDRESS + regs[(bank)].reg); } + +/* Initialize the GPIOs as defined on mainboard level. */ +void init_gpios(const struct gpio_config config[]) +{ + uint8_t bank, bit; + const struct gpio_config *pin; + + if (!config) + return; + /* Set up every GPIO in the table to the requested function. */ + for (pin = config; pin->use_sel != GPIO_LIST_END; pin++) { + /* Skip unsupported GPIO numbers. */ + if (pin->num > MAX_GPIO_NUM || pin->num == 13) + continue; + bank = pin->num / 32; + bit = pin->num % 32; + if (pin->use_sel == GPIO_MODE_GPIO) { + /* Setting level register first avoids possible short + * pulses on the pin if the output level differs from + * the register default value. + */ + if (pin->io_sel == GPIO_OUTPUT) + SETUP_GPIO_REG(level, bit, bank); + /* Now set the GPIO direction and NMI selection. */ + SETUP_GPIO_REG(io_sel, bit, bank); + SETUP_GPIO_REG(nmi_en, bit, bank); + } + /* Now set the pin mode as requested */ + SETUP_GPIO_REG(use_sel, bit, bank); + /* The extended functions like inverting and blinking are only + * supported by GPIOs on bank 0. + */ + if (bank) + continue; + /* Blinking is available only for outputs */ + if (pin->io_sel == GPIO_OUTPUT) + SETUP_GPIO_REG(blink_en, bit, bank); + /* Inverting is available only for inputs */ + if (pin->io_sel == GPIO_INPUT) + SETUP_GPIO_REG(invert_input, bit, bank); + } +} + +/* Get GPIO pin value */ +int gpio_get(gpio_t gpio) +{ + uint8_t bank, bit; + + bank = gpio / 32; + bit = gpio % 32; + return (inl(GPIO_BASE_ADDRESS + regs[bank].level) & (1 << bit)) ? 1 : 0; +} + +/* Set GPIO pin value */ +void gpio_set(gpio_t gpio, int value) +{ + uint32_t reg; + uint8_t bank, bit; + + bank = gpio / 32; + bit = gpio % 32; + reg = inl(GPIO_BASE_ADDRESS + regs[bank].level); + reg &= ~(1 << bit); + reg |= (!!value << bit); + outl(reg, GPIO_BASE_ADDRESS + regs[bank].level); +} diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h b/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h new file mode 100644 index 0000000000..07deeb08d6 --- /dev/null +++ b/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h @@ -0,0 +1,130 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2017 Siemens AG + * + * 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 FSP_BROADWELL_DE_GPIO_H_ +#define FSP_BROADWELL_DE_GPIO_H_ + +#include +#include + +/* Chipset owned GPIO configuration registers */ +#define GPIO_1_USE_SEL 0x00 +#define GPIO_1_IO_SEL 0x04 +#define GPIO_1_LVL 0x0c +#define GPIO_1_BLINK 0x18 +#define GPIO_1_NMI_EN 0x28 +#define GPIO_1_INVERT 0x2c +#define GPIO_2_USE_SEL 0x30 +#define GPIO_2_IO_SEL 0x34 +#define GPIO_2_LVL 0x38 +#define GPIO_2_NMI_EN 0x3c +#define GPIO_3_USE_SEL 0x40 +#define GPIO_3_IO_SEL 0x44 +#define GPIO_3_LVL 0x48 +#define GPIO_3_NMI_EN 0x50 +#define REG_INVALID 0xff + +/* The pin can either be a GPIO or connected to the native function. */ +#define GPIO_MODE_NATIVE 0 +#define GPIO_MODE_GPIO 1 +/* Once configured as GPIO the pin can be an input or an output. */ +#define GPIO_OUTPUT 0 +#define GPIO_INPUT 1 +#define GPIO_NMI_EN 1 +/* For output GPIO mode the pin can either drive high or low level. */ +#define GPIO_OUT_LEVEL_LOW 0 +#define GPIO_OUT_LEVEL_HIGH 1 +/* The following functions are only valid for GPIO bank 1. */ +#define GPIO_OUT_BLINK 1 +#define GPIO_IN_INVERT 1 + +#define GPIO_NUM_BANKS 3 +#define MAX_GPIO_NUM 75 /* 0 based GPIO number */ +#define GPIO_LIST_END 0xff + +/* Define possible GPIO configurations. */ +#define PCH_GPIO_END \ + { .use_sel = GPIO_LIST_END } + +#define PCH_GPIO_NATIVE(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_NATIVE } + +#define PCH_GPIO_INPUT(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_INPUT } + +#define PCH_GPIO_INPUT_INVERT(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_INPUT, \ + .invert_input = GPIO_IN_INVERT } + +#define PCH_GPIO_INPUT_NMI(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_INPUT, \ + .nmi_en = GPIO_NMI_EN } + +#define PCH_GPIO_OUT_LOW(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_OUTPUT, \ + .level = GPIO_OUT_LEVEL_LOW } + +#define PCH_GPIO_OUT_HIGH(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_OUTPUT, \ + .level = GPIO_OUT_LEVEL_HIGH } + +#define PCH_GPIO_OUT_BLINK(gpio) { \ + .num = (gpio), \ + .use_sel = GPIO_MODE_GPIO, \ + .io_sel = GPIO_OUTPUT, \ + .blink_en = GPIO_OUT_BLINK } + +struct gpio_config { + uint8_t num; + uint8_t use_sel; + uint8_t io_sel; + uint8_t level; + uint8_t blink_en; + uint8_t nmi_en; + uint8_t invert_input; +} __packed; + +/* Unfortunately the register layout is not linear between different GPIO banks. + * In addition not every bank has all the functions so that some registers might + * be missing on a particular bank. To make the code better readable introduce a + * wrapper structure for the register addresses for every bank. + */ +struct gpio_config_regs { + uint8_t use_sel; + uint8_t io_sel; + uint8_t level; + uint8_t nmi_en; + uint8_t blink_en; + uint8_t invert_input; +}; + +/* Define gpio_t here to be able to use src/include/gpio.h for gpio_set() and + gpio_get().*/ +typedef uint8_t gpio_t; + +/* Configure GPIOs with mainboard provided settings */ +void init_gpios(const struct gpio_config config[]); + +#endif /* FSP_BROADWELL_DE_GPIO_H_ */ diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h b/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h index ca842997a9..ac04c63af7 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Google Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2017 Siemens AG * * 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 @@ -63,4 +64,8 @@ #define ACPI_BASE_ADDRESS 0x400 #define ACPI_BASE_SIZE 0x80 +/* GPIO Base Address */ +#define GPIO_BASE_ADDRESS 0x500 +#define GPIO_BASE_SIZE 0x80 + #endif /* _SOC_IOMAP_H_ */ diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h index 6a91f8fd2d..3f9c2024f7 100644 --- a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h +++ b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h @@ -21,6 +21,9 @@ #include /* LPC Interface Bridge PCI Configuration Registers */ +#define GPIO_BASE_ADR_OFFSET 0x48 +#define GPIO_CTRL_OFFSET 0x4c +#define GPIO_DECODE_ENABLE (1 << 4) #define REVID 0x08 #define PIRQ_RCR1 0x60 #define SIRQ_CNTL 0x64 diff --git a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c index 5754ec00a5..d5d0a96b56 100644 --- a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c +++ b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c @@ -3,6 +3,7 @@ * * Copyright (C) 2013 Google Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2017 Siemens AG * * 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 @@ -32,6 +33,7 @@ #include #include #include +#include #include static void init_rtc(void) @@ -45,6 +47,16 @@ static void init_rtc(void) cmos_init(gen_pmcon3 & RTC_PWR_STS); } +/* Set up IO address range and enable it for the GPIO block. */ +static void setup_gpio_io_address(void) +{ + pci_write_config32(PCI_DEV(0, LPC_DEV, LPC_FUNC), GPIO_BASE_ADR_OFFSET, + GPIO_BASE_ADDRESS); + pci_write_config8(PCI_DEV(0, LPC_DEV, LPC_FUNC), GPIO_CTRL_OFFSET, + GPIO_DECODE_ENABLE); +} + + /* Entry from cache-as-ram.inc. */ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header) { @@ -58,6 +70,7 @@ void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header) } console_init(); init_rtc(); + setup_gpio_io_address(); /* Call into mainboard. */ post_code(0x41); diff --git a/src/soc/intel/fsp_broadwell_de/southcluster.c b/src/soc/intel/fsp_broadwell_de/southcluster.c index e8c8706a5c..3bf5429e39 100644 --- a/src/soc/intel/fsp_broadwell_de/southcluster.c +++ b/src/soc/intel/fsp_broadwell_de/southcluster.c @@ -4,6 +4,7 @@ * Copyright (C) 2008-2009 coresystems GmbH * Copyright (C) 2013 Google Inc. * Copyright (C) 2015-2016 Intel Corp. + * Copyright (C) 2017 Siemens AG * * 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 @@ -196,6 +197,17 @@ static void sc_add_io_resources(device_t dev) res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER; res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + + /* Add the resource for GPIOs */ + res = new_resource(dev, GPIO_BASE_ADR_OFFSET); + res->base = GPIO_BASE_ADDRESS; + res->size = GPIO_BASE_SIZE; + res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED; + /* There is a separated enable-bit in GPIO_CTRL-register. It was set + * already in romstage but FSP was active in the meantime and could have + * cleared it. Set it here again to enable allocated IO-space for sure. + */ + pci_write_config8(dev, GPIO_CTRL_OFFSET, GPIO_DECODE_ENABLE); } static void sc_read_resources(device_t dev) -- cgit v1.2.3