From mboxrd@z Thu Jan 1 00:00:00 1970 From: Tim Harvey Date: Fri, 22 Feb 2019 10:03:08 -0800 Subject: [U-Boot] [RFC 11/22] gpio: add thunderx gpio driver In-Reply-To: <20190222180319.32221-1-tharvey@gateworks.com> References: <20190222180319.32221-1-tharvey@gateworks.com> Message-ID: <20190222180319.32221-12-tharvey@gateworks.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Signed-off-by: Tim Harvey --- configs/thunderx_81xx_defconfig | 4 + drivers/gpio/Kconfig | 7 ++ drivers/gpio/Makefile | 1 + drivers/gpio/thunderx_gpio.c | 189 ++++++++++++++++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 drivers/gpio/thunderx_gpio.c diff --git a/configs/thunderx_81xx_defconfig b/configs/thunderx_81xx_defconfig index 3ec7d6cd4f..d07b0e5804 100644 --- a/configs/thunderx_81xx_defconfig +++ b/configs/thunderx_81xx_defconfig @@ -21,10 +21,14 @@ CONFIG_SYS_PROMPT="ThunderX_81XX> " # CONFIG_CMD_SAVEENV is not set # CONFIG_CMD_ENV_EXISTS is not set # CONFIG_CMD_FLASH is not set +CONFIG_CMD_GPIO=y CONFIG_CMD_PCI=y # CONFIG_CMD_NET is not set CONFIG_DEFAULT_DEVICE_TREE="thunderx-81xx" CONFIG_DM=y +CONFIG_DM_GPIO=y +CONFIG_LED=y +CONFIG_LED_GPIO=y # CONFIG_MMC is not set CONFIG_PCI=y CONFIG_DM_PCI=y diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5cd8b34400..b34f66969a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -238,6 +238,13 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config THUNDERX_GPIO + bool "Cavium ThunderX GPIO driver" + depends on DM_GPIO + default y + help + Say yes here to support Cavium ThunderX GPIOs. + config STM32F7_GPIO bool "ST STM32 GPIO driver" depends on DM_GPIO && (STM32 || ARCH_STM32MP) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f186120684..4c22c5f1d2 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o obj-$(CONFIG_HSDK_CREG_GPIO) += hsdk-creg-gpio.o obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o +obj-$(CONFIG_THUNDERX_GPIO) += thunderx_gpio.o obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(SPL_)PCF8575_GPIO) += pcf8575_gpio.o diff --git a/drivers/gpio/thunderx_gpio.c b/drivers/gpio/thunderx_gpio.c new file mode 100644 index 0000000000..5d38ddccdd --- /dev/null +++ b/drivers/gpio/thunderx_gpio.c @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2018, Cavium Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Returns the bit value to write or read based on the offset */ +#define GPIO_BIT(x) (1ULL << ((x) & 0x3f)) + +#define GPIO_RX_DAT (0x0) +#define GPIO_TX_SET (0x8) +#define GPIO_TX_CLR (0x10) +#define GPIO_CONST (0x90) +#define GPIO_RX1_DAT (0x1400) +#define GPIO_TX1_SET (0x1408) +#define GPIO_TX1_CLR (0x1410) + +/** Returns the offset to the output register based on the offset and value */ +#define GPIO_TX_REG(offset, value) \ + ((offset) >= 64 ? ((value) ? GPIO_TX1_SET : GPIO_TX1_CLR) : \ + ((value) ? GPIO_TX_SET : GPIO_TX_CLR)) + +/** Returns the offset to the input data register based on the offset */ +#define GPIO_RX_DAT_REG(offset) ((offset >= 64) ? GPIO_RX1_DAT : GPIO_RX_DAT) + +/** Returns the bit configuration register based on the offset */ +#define GPIO_BIT_CFG(x) (0x400 + 8 * (x)) +#define GPIO_BIT_CFG_FN(x) (((x) >> 16) & 0x3ff) +#define GPIO_BIT_CFG_TX_OE(x) ((x) & 0x1) +#define GPIO_BIT_CFG_RX_DAT(x) ((x) & 0x1) + +union gpio_const { + u64 u; + struct { + u64 gpios:8; /** Number of GPIOs implemented */ + u64 pp:8; /** Number of PP vectors */ + u64:48; /* Reserved */ + } s; +}; + +struct thunderx_gpio { + void __iomem *baseaddr; +}; + +static int thunderx_gpio_dir_input(struct udevice *dev, unsigned offset) +{ + struct thunderx_gpio *gpio = dev_get_priv(dev); + dev_dbg(dev, "%s: offset=%u\n", __func__, offset); + clrbits_le64(gpio->baseaddr + GPIO_BIT_CFG(offset), + (0x3ffUL << 16) | 4UL | 1UL); + return 0; +} + +static int thunderx_gpio_dir_output(struct udevice *dev, unsigned offset, + int value) +{ + struct thunderx_gpio *gpio = dev_get_priv(dev); + + dev_dbg(dev, "%s: offset=%u value=%d\n", __func__, offset, value); + writeq(GPIO_BIT(offset), gpio->baseaddr + GPIO_TX_REG(offset, value)); + + clrsetbits_le64(gpio->baseaddr + GPIO_BIT_CFG(offset), + ((0x3ffUL << 16) | 4UL), 1UL); + return 0; +} + +static int thunderx_gpio_get_value(struct udevice *dev, + unsigned offset) +{ + struct thunderx_gpio *gpio = dev_get_priv(dev); + u64 reg = readq(gpio->baseaddr + GPIO_RX_DAT_REG(offset)); + + dev_dbg(dev, "%s: offset=%u value=%d\n", __func__, offset, + !!(reg & GPIO_BIT(offset))); + + return !!(reg & GPIO_BIT(offset)); +} + +static int thunderx_gpio_set_value(struct udevice *dev, + unsigned offset, int value) +{ + struct thunderx_gpio *gpio = dev_get_priv(dev); + + dev_dbg(dev, "%s: offset=%u value=%d\n", __func__, offset, value); + writeq(GPIO_BIT(offset), gpio->baseaddr + GPIO_TX_REG(offset, value)); + + return 0; + +} + +static int thunderx_gpio_get_function(struct udevice *dev, + unsigned offset) +{ + struct thunderx_gpio *gpio = dev_get_priv(dev); + u64 pinsel = readl(gpio->baseaddr + GPIO_BIT_CFG(offset)); + + dev_dbg(dev, "%s: offset=%u pinsel:0x%llx\n", __func__, offset, pinsel); + if (GPIO_BIT_CFG_FN(pinsel)) + return GPIOF_FUNC; + else if (GPIO_BIT_CFG_TX_OE(pinsel)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static int thunderx_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + if (args->args_count < 1) + return -EINVAL; + + desc->offset = args->args[0]; + desc->flags = 0; + if (args->args_count > 1) { + if (args->args[1] & GPIO_ACTIVE_LOW) + desc->flags |= GPIOD_ACTIVE_LOW; + /* In the future add tri-state flag support */ + } + return 0; +} + +static const struct dm_gpio_ops thunderx_gpio_ops = { + .direction_input = thunderx_gpio_dir_input, + .direction_output = thunderx_gpio_dir_output, + .get_value = thunderx_gpio_get_value, + .set_value = thunderx_gpio_set_value, + .get_function = thunderx_gpio_get_function, + .xlate = thunderx_gpio_xlate, +}; + +static int thunderx_pci_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct thunderx_gpio *priv = dev_get_priv(dev); + pci_dev_t bdf = dm_pci_get_bdf(dev); + union gpio_const gpio_const; + size_t size; + + dev->req_seq = PCI_FUNC(bdf); + priv->baseaddr = dm_pci_map_bar(dev, 0, &size, PCI_REGION_MEM); + if (!priv->baseaddr) { + dev_err(dev, "%s: Could not get base address\n", __func__); + return -EINVAL; + } + + gpio_const.u = readq(priv->baseaddr + GPIO_CONST); + + dev_dbg(dev, "%s: base address:%p of_offset:%ld pin count: %d\n", + __func__, priv->baseaddr, dev->node.of_offset, + gpio_const.s.gpios); + + uc_priv->gpio_count = gpio_const.s.gpios; + uc_priv->bank_name = strdup(dev->name); + + return 0; +} + +static const struct udevice_id thunderx_gpio_ids[] = { + { .compatible = "cavium,thunder-8890-gpio" }, + { .compatible = "cavium,gpio" }, + { .compatible = "cavium,thunderx-gpio" }, + { } +}; + +U_BOOT_DRIVER(thunderx_pci_gpio) = { + .name = "gpio_thunderx", + .id = UCLASS_GPIO, + .of_match = of_match_ptr(thunderx_gpio_ids), + .probe = thunderx_pci_gpio_probe, + .priv_auto_alloc_size = sizeof(struct thunderx_gpio), + .ops = &thunderx_gpio_ops, +}; + +static struct pci_device_id thunderx_pci_gpio_supported[] = { + { PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_THUNDERX_GPIO) }, + { }, +}; + +U_BOOT_PCI_DEVICE(thunderx_pci_gpio, thunderx_pci_gpio_supported); + -- 2.17.1