All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Roese <sr@denx.de>
To: u-boot@lists.denx.de
Subject: [PATCH v2 01/10] gpio: octeon_gpio: Add GPIO controller driver for Octeon
Date: Thu, 23 Jul 2020 12:17:14 +0200	[thread overview]
Message-ID: <20200723101724.953325-2-sr@denx.de> (raw)
In-Reply-To: <20200723101724.953325-1-sr@denx.de>

From: Suneel Garapati <sgarapati@marvell.com>

Add support for GPIO controllers found on Octeon II/III and Octeon TX
TX2 SoC platforms.

Signed-off-by: Aaron Williams <awilliams@marvell.com>
Signed-off-by: Suneel Garapati <sgarapati@marvell.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>

---

Changes in v2:
- Tested on MIPS Octeon and ARM Octeon TX2
- Removed "struct pci_device_id" definition and U_BOOT_PCI_DEVICE()
  as its not needed for the PCI based probing on Octeon TX2
- Added "depends on DM_PCI" to Kconfig

Changes in v1:
- Removed common.h and reduced headers as suggested by Daniel

 drivers/gpio/Kconfig       |  10 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/octeon_gpio.c | 242 +++++++++++++++++++++++++++++++++++++
 3 files changed, 253 insertions(+)
 create mode 100644 drivers/gpio/octeon_gpio.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0e8ad9530d..f8a48dc675 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -335,6 +335,16 @@ config PIC32_GPIO
 	help
 	  Say yes here to support Microchip PIC32 GPIOs.
 
+config OCTEON_GPIO
+	bool "Octeon II/III/TX/TX2 GPIO driver"
+	depends on DM_GPIO && DM_PCI &&	(ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2)
+	default y
+	help
+	  Add support for the Marvell Octeon GPIO driver. This is used with
+	  various Octeon parts such as Octeon II/III and OcteonTX/TX2.
+	  Octeon II/III has 32 GPIOs (count defined via DT) and OcteonTX/TX2
+	  has 64 GPIOs (count defined via internal register).
+
 config STM32_GPIO
 	bool "ST STM32 GPIO driver"
 	depends on DM_GPIO && (ARCH_STM32 || ARCH_STM32MP)
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 7638259007..eb6364adb4 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -58,6 +58,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_OCTEON_GPIO)	+= octeon_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/octeon_gpio.c b/drivers/gpio/octeon_gpio.c
new file mode 100644
index 0000000000..45acaadcdb
--- /dev/null
+++ b/drivers/gpio/octeon_gpio.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier:    GPL-2.0
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ *
+ * (C) Copyright 2011
+ * eInfochips Ltd. <www.einfochips.com>
+ * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com>
+ *
+ * (C) Copyright 2010
+ * Marvell Semiconductor <www.marvell.com>
+ */
+
+#include <dm.h>
+#include <pci.h>
+#include <pci_ids.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/compat.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/* Returns the bit value to write or read based on the offset */
+#define GPIO_BIT(x)		BIT_ULL((x) & 0x3f)
+
+#define GPIO_RX_DAT		0x00
+#define GPIO_TX_SET		0x08
+#define GPIO_TX_CLR		0x10
+#define GPIO_CONST		0x90	/* OcteonTX only */
+
+/* Offset to register-set for 2nd GPIOs (> 63), OcteonTX only */
+#define GPIO1_OFFSET		0x1400
+
+/* GPIO_CONST register bits */
+#define GPIO_CONST_GPIOS_MASK	GENMASK_ULL(7, 0)
+
+/* GPIO_BIT_CFG register bits */
+#define GPIO_BIT_CFG_TX_OE	BIT_ULL(0)
+#define GPIO_BIT_CFG_PIN_XOR	BIT_ULL(1)
+#define GPIO_BIT_CFG_INT_EN	BIT_ULL(2)
+#define GPIO_BIT_CFG_PIN_SEL_MASK GENMASK_ULL(26, 16)
+
+enum {
+	PROBE_PCI = 0,		/* PCI based probing */
+	PROBE_DT,		/* DT based probing */
+};
+
+struct octeon_gpio_data {
+	int probe;
+	u32 reg_offs;
+	u32 gpio_bit_cfg_offs;
+};
+
+struct octeon_gpio {
+	void __iomem *base;
+	const struct octeon_gpio_data *data;
+};
+
+/* Returns the offset to the output register based on the offset and value */
+static u32 gpio_tx_reg(int offset, int value)
+{
+	u32 ret;
+
+	ret = value ? GPIO_TX_SET : GPIO_TX_CLR;
+	if (offset > 63)
+		ret += GPIO1_OFFSET;
+
+	return ret;
+}
+
+/* Returns the offset to the input data register based on the offset */
+static u32 gpio_rx_dat_reg(int offset)
+{
+	u32 ret;
+
+	ret = GPIO_RX_DAT;
+	if (offset > 63)
+		ret += GPIO1_OFFSET;
+
+	return ret;
+}
+
+static int octeon_gpio_dir_input(struct udevice *dev, unsigned int offset)
+{
+	struct octeon_gpio *gpio = dev_get_priv(dev);
+
+	debug("%s(%s, %u)\n", __func__, dev->name, offset);
+	clrbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
+		   GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_PIN_XOR |
+		   GPIO_BIT_CFG_INT_EN | GPIO_BIT_CFG_PIN_SEL_MASK);
+
+	return 0;
+}
+
+static int octeon_gpio_dir_output(struct udevice *dev, unsigned int offset,
+				  int value)
+{
+	struct octeon_gpio *gpio = dev_get_priv(dev);
+
+	debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
+	writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
+	       gpio_tx_reg(offset, value));
+
+	clrsetbits_64(gpio->base + gpio->data->gpio_bit_cfg_offs + 8 * offset,
+		      GPIO_BIT_CFG_PIN_SEL_MASK | GPIO_BIT_CFG_INT_EN,
+		      GPIO_BIT_CFG_TX_OE);
+
+	return 0;
+}
+
+static int octeon_gpio_get_value(struct udevice *dev, unsigned int offset)
+{
+	struct octeon_gpio *gpio = dev_get_priv(dev);
+	u64 reg = readq(gpio->base + gpio->data->reg_offs +
+			gpio_rx_dat_reg(offset));
+
+	debug("%s(%s, %u): value: %d\n", __func__, dev->name, offset,
+	      !!(reg & GPIO_BIT(offset)));
+
+	return !!(reg & GPIO_BIT(offset));
+}
+
+static int octeon_gpio_set_value(struct udevice *dev,
+				 unsigned int offset, int value)
+{
+	struct octeon_gpio *gpio = dev_get_priv(dev);
+
+	debug("%s(%s, %u, %d)\n", __func__, dev->name, offset, value);
+	writeq(GPIO_BIT(offset), gpio->base + gpio->data->reg_offs +
+	       gpio_tx_reg(offset, value));
+
+	return 0;
+}
+
+static int octeon_gpio_get_function(struct udevice *dev, unsigned int offset)
+{
+	struct octeon_gpio *gpio = dev_get_priv(dev);
+	u64 val = readq(gpio->base + gpio->data->gpio_bit_cfg_offs +
+			8 * offset);
+	int pin_sel;
+
+	debug("%s(%s, %u): GPIO_BIT_CFG: 0x%llx\n", __func__, dev->name,
+	      offset, val);
+	pin_sel = FIELD_GET(GPIO_BIT_CFG_PIN_SEL_MASK, val);
+	if (pin_sel)
+		return GPIOF_FUNC;
+	else if (val & GPIO_BIT_CFG_TX_OE)
+		return GPIOF_OUTPUT;
+	else
+		return GPIOF_INPUT;
+}
+
+static int octeon_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 octeon_gpio_ops = {
+	.direction_input	= octeon_gpio_dir_input,
+	.direction_output	= octeon_gpio_dir_output,
+	.get_value		= octeon_gpio_get_value,
+	.set_value		= octeon_gpio_set_value,
+	.get_function		= octeon_gpio_get_function,
+	.xlate			= octeon_gpio_xlate,
+};
+
+static int octeon_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct octeon_gpio *priv = dev_get_priv(dev);
+	char *end;
+
+	priv->data = (const struct octeon_gpio_data *)dev_get_driver_data(dev);
+
+	if (priv->data->probe == PROBE_PCI) {
+		priv->base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0,
+					    PCI_REGION_MEM);
+		uc_priv->gpio_count = readq(priv->base +
+					    priv->data->reg_offs + GPIO_CONST) &
+			GPIO_CONST_GPIOS_MASK;
+	} else {
+		priv->base = dev_remap_addr(dev);
+		uc_priv->gpio_count = ofnode_read_u32_default(dev->node,
+							      "nr-gpios", 32);
+	}
+
+	if (!priv->base) {
+		debug("%s(%s): Could not get base address\n",
+		      __func__, dev->name);
+		return -ENODEV;
+	}
+
+	uc_priv->bank_name  = strdup(dev->name);
+	end = strchr(uc_priv->bank_name, '@');
+	end[0] = 'A' + dev->seq;
+	end[1] = '\0';
+
+	debug("%s(%s): base address: %p, pin count: %d\n",
+	      __func__, dev->name, priv->base, uc_priv->gpio_count);
+
+	return 0;
+}
+
+static const struct octeon_gpio_data gpio_octeon_data = {
+	.probe = PROBE_DT,
+	.reg_offs = 0x80,
+	.gpio_bit_cfg_offs = 0x100,
+};
+
+static const struct octeon_gpio_data gpio_octeontx_data = {
+	.probe = PROBE_PCI,
+	.reg_offs = 0x00,
+	.gpio_bit_cfg_offs = 0x400,
+};
+
+static const struct udevice_id octeon_gpio_ids[] = {
+	{ .compatible = "cavium,thunder-8890-gpio",
+	  .data = (ulong)&gpio_octeontx_data },
+	{ .compatible = "cavium,octeon-7890-gpio",
+	  .data = (ulong)&gpio_octeon_data },
+	{ }
+};
+
+U_BOOT_DRIVER(octeon_gpio) = {
+	.name	= "octeon_gpio",
+	.id	= UCLASS_GPIO,
+	.of_match = of_match_ptr(octeon_gpio_ids),
+	.probe = octeon_gpio_probe,
+	.priv_auto_alloc_size = sizeof(struct octeon_gpio),
+	.ops	= &octeon_gpio_ops,
+	.flags	= DM_FLAG_PRE_RELOC,
+};
-- 
2.27.0

  reply	other threads:[~2020-07-23 10:17 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-23 10:17 [PATCH v2 00/10] mips: octeon: Misc Octeon drivers, DT and Kconfig / defconfig updates Stefan Roese
2020-07-23 10:17 ` Stefan Roese [this message]
2020-07-23 10:17 ` [PATCH v2 02/10] mips: octeon: mrvl,cn73xx.dtsi: Add GPIO DT nodes Stefan Roese
2020-07-23 10:17 ` [PATCH v2 03/10] mips: octeon: dts: Add I2C " Stefan Roese
2020-07-23 10:17 ` [PATCH v2 04/10] clk: clk_octeon: Add simple MIPS Octeon clock driver Stefan Roese
2020-07-23 10:17 ` [PATCH v2 05/10] mips: octeon: dts: Add Octeon clock driver DT nodes Stefan Roese
2020-07-23 10:17 ` [PATCH v2 06/10] drivers: spi: Add SPI controller driver for Octeon Stefan Roese
2020-07-24 13:56   ` Daniel Schwierzeck
2020-07-24 14:27     ` Stefan Roese
2020-07-30  5:49     ` Stefan Roese
2020-07-30  6:23       ` Stefan Roese
2020-07-30 11:00         ` Daniel Schwierzeck
2020-07-30 11:42           ` Stefan Roese
2020-07-30  7:50     ` Jagan Teki
2020-07-30  7:53       ` Stefan Roese
2020-07-30  7:44   ` Jagan Teki
2020-07-30  8:06     ` Stefan Roese
2020-07-23 10:17 ` [PATCH v2 07/10] mips: octeon: mrvl,cn73xx.dtsi: Add SPI DT node Stefan Roese
2020-07-23 10:17 ` [PATCH v2 08/10] mips: octeon: mrvl, octeon-ebb7304.dts: Add SPI flash " Stefan Roese
2020-07-23 10:17 ` [PATCH v2 09/10] mips: octeon: Update Octeon Kconfig Stefan Roese
2020-07-23 10:17 ` [PATCH v2 10/10] mips: octeon: Update EBB7304 defconfig Stefan Roese
2020-07-30 11:56 [PATCH v2 00/10] mips: octeon: Misc Octeon drivers, DT and Kconfig / defconfig updates Stefan Roese
2020-07-30 11:56 ` [PATCH v2 01/10] gpio: octeon_gpio: Add GPIO controller driver for Octeon Stefan Roese
2020-08-03 19:10   ` Daniel Schwierzeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200723101724.953325-2-sr@denx.de \
    --to=sr@denx.de \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.