diff options
author | Werner Zeh <werner.zeh@siemens.com> | 2017-10-16 08:37:28 +0200 |
---|---|---|
committer | Aaron Durbin <adurbin@chromium.org> | 2017-10-19 15:13:40 +0000 |
commit | 4bf11ce2b5de81ec0bd6799f4830a48c7376c122 (patch) | |
tree | d2e34db2f81666fcd969930a2f2565e8e64cc045 /src/soc/intel/fsp_broadwell_de/gpio.c | |
parent | e77d588ee46bfdff1a152f166eca84e3c5827665 (diff) |
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.c | 109 |
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); +} |