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