summaryrefslogtreecommitdiff
path: root/src/soc/intel/fsp_broadwell_de/gpio.c
diff options
context:
space:
mode:
authorWerner Zeh <werner.zeh@siemens.com>2017-10-16 08:37:28 +0200
committerAaron Durbin <adurbin@chromium.org>2017-10-19 15:13:40 +0000
commit4bf11ce2b5de81ec0bd6799f4830a48c7376c122 (patch)
treed2e34db2f81666fcd969930a2f2565e8e64cc045 /src/soc/intel/fsp_broadwell_de/gpio.c
parente77d588ee46bfdff1a152f166eca84e3c5827665 (diff)
downloadcoreboot-4bf11ce2b5de81ec0bd6799f4830a48c7376c122.tar.xz
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 <werner.zeh@siemens.com> Reviewed-on: https://review.coreboot.org/22034 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/soc/intel/fsp_broadwell_de/gpio.c')
-rw-r--r--src/soc/intel/fsp_broadwell_de/gpio.c109
1 files changed, 109 insertions, 0 deletions
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 <stdint.h>
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <gpio.h>
+#include <soc/pci_devs.h>
+#include <soc/lpc.h>
+#include <soc/iomap.h>
+#include <soc/gpio.h>
+
+/* 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);
+}