<p>Werner Zeh has uploaded this change for <strong>review</strong>.</p><p><a href="https://review.coreboot.org/22034">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">soc/fsp_broadwell_de: Add support for GPIO handling<br><br>Add functionality to initialize, set and read back GPIOs on FSP based<br>Broadwell-DE implementation.<br><br>Change-Id: Ibbd86e2142bbf5772eb4a91ebb9166c31d52476e<br>Signed-off-by: Werner Zeh <werner.zeh@siemens.com><br>---<br>M src/soc/intel/fsp_broadwell_de/Makefile.inc<br>A src/soc/intel/fsp_broadwell_de/gpio.c<br>A src/soc/intel/fsp_broadwell_de/include/soc/gpio.h<br>M src/soc/intel/fsp_broadwell_de/include/soc/iomap.h<br>M src/soc/intel/fsp_broadwell_de/include/soc/lpc.h<br>M src/soc/intel/fsp_broadwell_de/romstage/romstage.c<br>M src/soc/intel/fsp_broadwell_de/southcluster.c<br>7 files changed, 275 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://review.coreboot.org:29418/coreboot refs/changes/34/22034/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/src/soc/intel/fsp_broadwell_de/Makefile.inc b/src/soc/intel/fsp_broadwell_de/Makefile.inc<br>index 028c45d..2726ffa 100644<br>--- a/src/soc/intel/fsp_broadwell_de/Makefile.inc<br>+++ b/src/soc/intel/fsp_broadwell_de/Makefile.inc<br>@@ -11,6 +11,8 @@<br> subdirs-y += ../../../lib/fsp<br> subdirs-y += fsp<br> <br>+romstage-y += gpio.c<br>+<br> ramstage-y += spi.c<br> ramstage-y += cpu.c<br> ramstage-y += chip.c<br>@@ -25,6 +27,7 @@<br> ramstage-y += smbus_common.c<br> ramstage-y += smbus.c<br> ramstage-y += smi.c<br>+ramstage-y += gpio.c<br> ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c<br> ramstage-$(CONFIG_HAVE_SMI_HANDLER) += pmutil.c<br> smm-$(CONFIG_HAVE_SMI_HANDLER) += pmutil.c<br>diff --git a/src/soc/intel/fsp_broadwell_de/gpio.c b/src/soc/intel/fsp_broadwell_de/gpio.c<br>new file mode 100644<br>index 0000000..95a600f<br>--- /dev/null<br>+++ b/src/soc/intel/fsp_broadwell_de/gpio.c<br>@@ -0,0 +1,108 @@<br>+/*<br>+ * This file is part of the coreboot project.<br>+ *<br>+ * Copyright (C) 2017 Siemens AG<br>+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation; version 2 of the License.<br>+ *<br>+ * This program is distributed in the hope that it will be useful,<br>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>+ * GNU General Public License for more details.<br>+ */<br>+<br>+#include <stdint.h><br>+#include <arch/io.h><br>+#include <device/device.h><br>+#include <device/pci.h><br>+#include <soc/pci_devs.h><br>+#include <soc/lpc.h><br>+#include <soc/iomap.h><br>+#include <soc/gpio.h><br>+<br>+/* Use a wrapper for register addresses for different banks. */<br>+const static struct gpio_config_regs regs[GPIO_NUM_BANKS] = {<br>+ [0] = { .use_sel = GPIO_1_USE_SEL, .io_sel = GPIO_1_IO_SEL,<br>+ .level = GPIO_1_LVL, .nmi_en = GPIO_1_NMI_EN,<br>+ .blink_en = GPIO_1_BLINK, .invert_input = GPIO_1_INVERT },<br>+ [1] = { .use_sel = GPIO_2_USE_SEL, .io_sel = GPIO_2_IO_SEL,<br>+ .level = GPIO_2_LVL, .nmi_en = GPIO_2_NMI_EN,<br>+ .blink_en = REG_INVALID, .invert_input = REG_INVALID },<br>+ [2] = { .use_sel = GPIO_3_USE_SEL, .io_sel = GPIO_3_IO_SEL,<br>+ .level = GPIO_3_LVL, .nmi_en = GPIO_3_NMI_EN,<br>+ .blink_en = REG_INVALID, .invert_input = REG_INVALID },<br>+ };<br>+<br>+#define SETUP_GPIO_REG(reg, bit, bank) { uint32_t val; \<br>+ val = inl(GPIO_BASE_ADDRESS + regs[bank].reg); \<br>+ val &= ~(1 << bit); \<br>+ val |= (pin->reg << bit); \<br>+ outl(val, GPIO_BASE_ADDRESS + regs[bank].reg); }<br>+<br>+/* Initialize the GPIOs as defined on mainboard level. */<br>+void init_gpios(const struct gpio_config config[])<br>+{<br>+ uint8_t bank, bit;<br>+ const struct gpio_config *pin;<br>+<br>+ if (!config)<br>+ return;<br>+ /* Set up every GPIO in the table to the requested function. */<br>+ for (pin = config; pin->use_sel != GPIO_LIST_END; pin++) {<br>+ /* Skip unsupported GPIO numbers. */<br>+ if (pin->num > MAX_GPIO_NUM || pin->num == 13)<br>+ continue;<br>+ bank = pin->num / 32;<br>+ bit = pin->num % 32;<br>+ if (pin->use_sel == GPIO_MODE_GPIO) {<br>+ /* Setting level register first avoids possible short<br>+ * pulses on the pin if the output level differs from<br>+ * the register default value.<br>+ */<br>+ if (pin->io_sel == GPIO_OUTPUT)<br>+ SETUP_GPIO_REG(level, bit, bank);<br>+ /* Now set the GPIO direction and NMI selection. */<br>+ SETUP_GPIO_REG(io_sel, bit, bank);<br>+ SETUP_GPIO_REG(nmi_en, bit, bank);<br>+ }<br>+ /* Now set the pin mode as requested */<br>+ SETUP_GPIO_REG(use_sel, bit, bank);<br>+ /* The extended functions like inverting and blinking are only<br>+ * supported by GPIOs on bank 0.<br>+ */<br>+ if (bank)<br>+ continue;<br>+ /* Blinking is available only for outputs */<br>+ if (pin->io_sel == GPIO_OUTPUT)<br>+ SETUP_GPIO_REG(blink_en, bit, bank);<br>+ /* Inverting is available only for inputs */<br>+ if (pin->io_sel == GPIO_INPUT)<br>+ SETUP_GPIO_REG(invert_input, bit, bank);<br>+ }<br>+}<br>+<br>+/* Get GPIO pin value */<br>+uint8_t get_gpio(uint8_t gpio_num)<br>+{<br>+ uint8_t bank, bit;<br>+<br>+ bank = gpio_num / 32;<br>+ bit = gpio_num % 32;<br>+ return (inl(GPIO_BASE_ADDRESS + regs[bank].level) & (1 << bit)) ? 1 : 0;<br>+}<br>+<br>+/* Set GPIO pin value */<br>+void set_gpio(uint8_t gpio_num, uint8_t value)<br>+{<br>+ uint32_t reg;<br>+ uint8_t bank, bit;<br>+<br>+ bank = gpio_num / 32;<br>+ bit = gpio_num % 32;<br>+ reg = inl(GPIO_BASE_ADDRESS + regs[bank].level);<br>+ reg &= ~(1 << bit);<br>+ reg |= (!!value << bit);<br>+ outl(reg, GPIO_BASE_ADDRESS + regs[bank].level);<br>+}<br>diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h b/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h<br>new file mode 100644<br>index 0000000..8795c72<br>--- /dev/null<br>+++ b/src/soc/intel/fsp_broadwell_de/include/soc/gpio.h<br>@@ -0,0 +1,132 @@<br>+/*<br>+ * This file is part of the coreboot project.<br>+ *<br>+ * Copyright (C) 2017 Siemens AG<br>+ *<br>+ * This program is free software; you can redistribute it and/or modify<br>+ * it under the terms of the GNU General Public License as published by<br>+ * the Free Software Foundation; version 2 of the License.<br>+ *<br>+ * This program is distributed in the hope that it will be useful,<br>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>+ * GNU General Public License for more details.<br>+ */<br>+#ifndef FSP_BROADWELL_DE_GPIO_H_<br>+#define FSP_BROADWELL_DE_GPIO_H_<br>+<br>+#include <stdint.h><br>+#include <compiler.h><br>+<br>+/* Chipset owned GPIO configuration registers */<br>+#define GPIO_1_USE_SEL 0x00<br>+#define GPIO_1_IO_SEL 0x04<br>+#define GPIO_1_LVL 0x0c<br>+#define GPIO_1_BLINK 0x18<br>+#define GPIO_1_NMI_EN 0x28<br>+#define GPIO_1_INVERT 0x2c<br>+#define GPIO_2_USE_SEL 0x30<br>+#define GPIO_2_IO_SEL 0x34<br>+#define GPIO_2_LVL 0x38<br>+#define GPIO_2_NMI_EN 0x3c<br>+#define GPIO_3_USE_SEL 0x40<br>+#define GPIO_3_IO_SEL 0x44<br>+#define GPIO_3_LVL 0x48<br>+#define GPIO_3_NMI_EN 0x50<br>+#define REG_INVALID 0xff<br>+<br>+/* The pin can either be a GPIO or connected to the native function. */<br>+#define GPIO_MODE_NATIVE 0<br>+#define GPIO_MODE_GPIO 1<br>+/* Once configured as GPIO the pin can be an input or an output. */<br>+#define GPIO_OUTPUT 0<br>+#define GPIO_INPUT 1<br>+#define GPIO_NMI_EN 1<br>+/* For output GPIO mode the pin can either drive high or low level. */<br>+#define GPIO_OUT_LEVEL_LOW 0<br>+#define GPIO_OUT_LEVEL_HIGH 1<br>+/* The following functions are only valid for GPIO bank 1.*/<br>+#define GPIO_OUT_BLINK 1<br>+#define GPIO_IN_INVERT 1<br>+<br>+#define GPIO_NUM_BANKS 3<br>+#define MAX_GPIO_NUM 75 /* 0 based GPIO number */<br>+#define GPIO_LIST_END 0xff<br>+<br>+/* Define possible GPIO configurations. */<br>+#define PCH_GPIO_END \<br>+ { .use_sel = GPIO_LIST_END }<br>+<br>+#define PCH_GPIO_NATIVE(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_NATIVE }<br>+<br>+#define PCH_GPIO_INPUT(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_INPUT }<br>+<br>+#define PCH_GPIO_INPUT_INVERT(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_INPUT, \<br>+ .invert_input = GPIO_IN_INVERT }<br>+<br>+#define PCH_GPIO_INPUT_NMI(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_INPUT, \<br>+ .nmi_en = GPIO_NMI_EN }<br>+<br>+#define PCH_GPIO_OUT_LOW(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_OUTPUT, \<br>+ .level = GPIO_OUT_LEVEL_LOW }<br>+<br>+#define PCH_GPIO_OUT_HIGH(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_OUTPUT, \<br>+ .level = GPIO_OUT_LEVEL_HIGH }<br>+<br>+#define PCH_GPIO_OUT_BLINK(gpio) { \<br>+ .num = gpio, \<br>+ .use_sel = GPIO_MODE_GPIO, \<br>+ .io_sel = GPIO_OUTPUT, \<br>+ .blink_en = GPIO_OUT_BLINK }<br>+<br>+struct gpio_config {<br>+ uint8_t num;<br>+ uint8_t use_sel;<br>+ uint8_t io_sel;<br>+ uint8_t level;<br>+ uint8_t blink_en;<br>+ uint8_t nmi_en;<br>+ uint8_t invert_input;<br>+} __packed;<br>+<br>+/* Unfortunately the register layout is not linear between different GPIO banks.<br>+ * In addition not every bank has all the functions so that some registers might<br>+ * be missing on a particular bank. To make the code better readable introduce a<br>+ * wrapper structure for the register addresses for every bank.<br>+ */<br>+struct gpio_config_regs {<br>+ uint8_t use_sel;<br>+ uint8_t io_sel;<br>+ uint8_t level;<br>+ uint8_t nmi_en;<br>+ uint8_t blink_en;<br>+ uint8_t invert_input;<br>+};<br>+<br>+/* Configure GPIOs with mainboard provided settings */<br>+void init_gpios(const struct gpio_config config[]);<br>+<br>+/* Get GPIO pin value */<br>+uint8_t get_gpio(uint8_t gpio_num);<br>+<br>+/* Set GPIO pin value */<br>+void set_gpio(uint8_t gpio_num, uint8_t value);<br>+<br>+#endif /* FSP_BROADWELL_DE_GPIO_H_ */<br>diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h b/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h<br>index ca84299..ac04c63 100644<br>--- a/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h<br>+++ b/src/soc/intel/fsp_broadwell_de/include/soc/iomap.h<br>@@ -3,6 +3,7 @@<br> *<br> * Copyright (C) 2013 Google Inc.<br> * Copyright (C) 2015-2016 Intel Corp.<br>+ * Copyright (C) 2017 Siemens AG<br> *<br> * This program is free software; you can redistribute it and/or modify<br> * it under the terms of the GNU General Public License as published by<br>@@ -63,4 +64,8 @@<br> #define ACPI_BASE_ADDRESS 0x400<br> #define ACPI_BASE_SIZE 0x80<br> <br>+/* GPIO Base Address */<br>+#define GPIO_BASE_ADDRESS 0x500<br>+#define GPIO_BASE_SIZE 0x80<br>+<br> #endif /* _SOC_IOMAP_H_ */<br>diff --git a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h<br>index 6a91f8f..3f9c202 100644<br>--- a/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h<br>+++ b/src/soc/intel/fsp_broadwell_de/include/soc/lpc.h<br>@@ -21,6 +21,9 @@<br> #include <arch/acpi.h><br> <br> /* LPC Interface Bridge PCI Configuration Registers */<br>+#define GPIO_BASE_ADR_OFFSET 0x48<br>+#define GPIO_CTRL_OFFSET 0x4c<br>+#define GPIO_DECODE_ENABLE (1 << 4)<br> #define REVID 0x08<br> #define PIRQ_RCR1 0x60<br> #define SIRQ_CNTL 0x64<br>diff --git a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c<br>index 5754ec0..d5d0a96 100644<br>--- a/src/soc/intel/fsp_broadwell_de/romstage/romstage.c<br>+++ b/src/soc/intel/fsp_broadwell_de/romstage/romstage.c<br>@@ -3,6 +3,7 @@<br> *<br> * Copyright (C) 2013 Google Inc.<br> * Copyright (C) 2015-2016 Intel Corp.<br>+ * Copyright (C) 2017 Siemens AG<br> *<br> * This program is free software; you can redistribute it and/or modify<br> * it under the terms of the GNU General Public License as published by<br>@@ -32,6 +33,7 @@<br> #include <soc/lpc.h><br> #include <soc/pci_devs.h><br> #include <soc/romstage.h><br>+#include <soc/gpio.h><br> #include <build.h><br> <br> static void init_rtc(void)<br>@@ -44,6 +46,16 @@<br> }<br> cmos_init(gen_pmcon3 & RTC_PWR_STS);<br> }<br>+<br>+/* Set up IO address range and enable it for the GPIO block. */<br>+static void setup_gpio_io_address(void)<br>+{<br>+ pci_write_config32(PCI_DEV(0, LPC_DEV, LPC_FUNC), GPIO_BASE_ADR_OFFSET,<br>+ GPIO_BASE_ADDRESS);<br>+ pci_write_config8(PCI_DEV(0, LPC_DEV, LPC_FUNC), GPIO_CTRL_OFFSET,<br>+ GPIO_DECODE_ENABLE);<br>+}<br>+<br> <br> /* Entry from cache-as-ram.inc. */<br> void *asmlinkage main(FSP_INFO_HEADER *fsp_info_header)<br>@@ -58,6 +70,7 @@<br> }<br> console_init();<br> init_rtc();<br>+ setup_gpio_io_address();<br> <br> /* Call into mainboard. */<br> post_code(0x41);<br>diff --git a/src/soc/intel/fsp_broadwell_de/southcluster.c b/src/soc/intel/fsp_broadwell_de/southcluster.c<br>index e8c8706..bd2628c 100644<br>--- a/src/soc/intel/fsp_broadwell_de/southcluster.c<br>+++ b/src/soc/intel/fsp_broadwell_de/southcluster.c<br>@@ -4,6 +4,7 @@<br> * Copyright (C) 2008-2009 coresystems GmbH<br> * Copyright (C) 2013 Google Inc.<br> * Copyright (C) 2015-2016 Intel Corp.<br>+ * Copyright (C) 2017 Siemens AG<br> *<br> * This program is free software; you can redistribute it and/or modify<br> * it under the terms of the GNU General Public License as published by<br>@@ -196,6 +197,16 @@<br> res->size = LPC_DEFAULT_IO_RANGE_UPPER - LPC_DEFAULT_IO_RANGE_LOWER;<br> res->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |<br> IORESOURCE_ASSIGNED | IORESOURCE_FIXED;<br>+<br>+ /* Add the resource for GPIOs */<br>+ res = new_resource(dev, GPIO_BASE_ADR_OFFSET);<br>+ res->base = GPIO_BASE_ADDRESS;<br>+ res->size = GPIO_BASE_SIZE;<br>+ res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;<br>+ /* There is a separated enable-bit in GPIO_CTRL-register, set it to<br>+ * enable allocated IO-space.<br>+ */<br>+ pci_write_config8(dev, GPIO_CTRL_OFFSET, GPIO_DECODE_ENABLE);<br> }<br> <br> static void sc_read_resources(device_t dev)<br></pre><p>To view, visit <a href="https://review.coreboot.org/22034">change 22034</a>. To unsubscribe, visit <a href="https://review.coreboot.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://review.coreboot.org/22034"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: coreboot </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ibbd86e2142bbf5772eb4a91ebb9166c31d52476e </div>
<div style="display:none"> Gerrit-Change-Number: 22034 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Werner Zeh <werner.zeh@siemens.com> </div>