Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Jun 2019 21:27:21 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r348880 - in head/sys: arm/mv arm64/conf conf
Message-ID:  <201906102127.x5ALRLt4078623@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: loos
Date: Mon Jun 10 21:27:21 2019
New Revision: 348880
URL: https://svnweb.freebsd.org/changeset/base/348880

Log:
  Add the GPIO driver for the North/South bridge in Marvell Armada 37x0.
  
  The A3700 has a different GPIO controller and thus, do not use the old (and
  shared) code for Marvell.
  
  The pinctrl driver, also part of the controller, is not supported yet (but
  the implementation should be straightforward).
  
  Sponsored by:	Rubicon Communications, LLC (Netgate)

Added:
  head/sys/arm/mv/a37x0_gpio.c   (contents, props changed)
Modified:
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files.arm64

Added: head/sys/arm/mv/a37x0_gpio.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/mv/a37x0_gpio.c	Mon Jun 10 21:27:21 2019	(r348880)
@@ -0,0 +1,352 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018-2019, Rubicon Communications, LLC (Netgate)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+static struct resource_spec a37x0_gpio_res_spec[] = {
+	{ SYS_RES_MEMORY, 0, RF_ACTIVE },	/* Pinctl / GPIO */
+	{ SYS_RES_MEMORY, 1, RF_ACTIVE },	/* Interrupts control */
+	{ -1, 0, 0 }
+};
+
+struct a37x0_gpio_softc {
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+	device_t		sc_busdev;
+	int			sc_type;
+	uint32_t		sc_max_pins;
+	uint32_t		sc_npins;
+	struct resource		*sc_mem_res[nitems(a37x0_gpio_res_spec) - 1];
+};
+
+/* Memory regions. */
+#define	A37X0_GPIO			0
+#define	A37X0_INTR			1
+
+/* North Bridge / South Bridge. */
+#define	A37X0_NB_GPIO			1
+#define	A37X0_SB_GPIO			2
+
+#define	A37X0_GPIO_WRITE(_sc, _off, _val)		\
+    bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off), (_val))
+#define	A37X0_GPIO_READ(_sc, _off)			\
+    bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off))
+
+#define	A37X0_GPIO_BIT(_p)		(1U << ((_p) % 32))
+#define	A37X0_GPIO_OUT_EN(_p)		(0x0 + ((_p) / 32) * 4)
+#define	A37X0_GPIO_LATCH(_p)		(0x8 + ((_p) / 32) * 4)
+#define	A37X0_GPIO_INPUT(_p)		(0x10 + ((_p) / 32) * 4)
+#define	A37X0_GPIO_OUTPUT(_p)		(0x18 + ((_p) / 32) * 4)
+#define	A37X0_GPIO_SEL			0x30
+
+
+static struct ofw_compat_data compat_data[] = {
+	{ "marvell,armada3710-nb-pinctrl",	A37X0_NB_GPIO },
+	{ "marvell,armada3710-sb-pinctrl",	A37X0_SB_GPIO },
+	{ NULL, 0 }
+};
+
+static phandle_t
+a37x0_gpio_get_node(device_t bus, device_t dev)
+{
+
+	return (ofw_bus_get_node(bus));
+}
+
+static device_t
+a37x0_gpio_get_bus(device_t dev)
+{
+	struct a37x0_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	return (sc->sc_busdev);
+}
+
+static int
+a37x0_gpio_pin_max(device_t dev, int *maxpin)
+{
+	struct a37x0_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+	*maxpin = sc->sc_npins - 1;
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	struct a37x0_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+	snprintf(name, GPIOMAXNAME, "pin %d", pin);
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	struct a37x0_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+	*caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct a37x0_gpio_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
+	if ((reg & A37X0_GPIO_BIT(pin)) != 0)
+		*flags = GPIO_PIN_OUTPUT;
+	else
+		*flags = GPIO_PIN_INPUT;
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct a37x0_gpio_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
+	if (flags & GPIO_PIN_OUTPUT)
+		reg |= A37X0_GPIO_BIT(pin);
+	else
+		reg &= ~A37X0_GPIO_BIT(pin);
+	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUT_EN(pin), reg);
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
+{
+	struct a37x0_gpio_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
+	if ((reg & A37X0_GPIO_BIT(pin)) != 0)
+		reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
+	else
+		reg = A37X0_GPIO_READ(sc, A37X0_GPIO_INPUT(pin));
+	*val = ((reg & A37X0_GPIO_BIT(pin)) != 0) ? 1 : 0;
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_set(device_t dev, uint32_t pin, unsigned int val)
+{
+	struct a37x0_gpio_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
+	if (val != 0)
+		reg |= A37X0_GPIO_BIT(pin);
+	else
+		reg &= ~A37X0_GPIO_BIT(pin);
+	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg);
+
+	return (0);
+}
+
+static int
+a37x0_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	struct a37x0_gpio_softc *sc;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	if (pin >= sc->sc_npins)
+		return (EINVAL);
+
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUT_EN(pin));
+	if ((reg & A37X0_GPIO_BIT(pin)) == 0)
+		return (EINVAL);
+	reg = A37X0_GPIO_READ(sc, A37X0_GPIO_OUTPUT(pin));
+	reg ^= A37X0_GPIO_BIT(pin);
+	A37X0_GPIO_WRITE(sc, A37X0_GPIO_OUTPUT(pin), reg);
+
+	return (0);
+}
+
+static int
+a37x0_gpio_probe(device_t dev)
+{
+	const char *desc;
+	struct a37x0_gpio_softc *sc;
+
+	if (!OF_hasprop(ofw_bus_get_node(dev), "gpio-controller"))
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	sc->sc_type = ofw_bus_search_compatible(
+	    device_get_parent(dev), compat_data)->ocd_data;
+	switch (sc->sc_type) {
+	case A37X0_NB_GPIO:
+		sc->sc_max_pins = 36;
+		desc = "Armada 37x0 North Bridge GPIO Controller";
+		break;
+	case A37X0_SB_GPIO:
+		sc->sc_max_pins = 30;
+		desc = "Armada 37x0 South Bridge GPIO Controller";
+		break;
+	default:
+		return (ENXIO);
+	}
+	device_set_desc(dev, desc);
+
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+a37x0_gpio_attach(device_t dev)
+{
+	int err, ncells;
+	pcell_t *ranges;
+	struct a37x0_gpio_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	/* Read and verify the "gpio-ranges" property. */
+	ncells = OF_getencprop_alloc(ofw_bus_get_node(dev), "gpio-ranges",
+	    (void **)&ranges);
+	if (ncells == -1)
+		return (ENXIO);
+	if (ncells != sizeof(*ranges) * 4 || ranges[1] != 0 || ranges[2] != 0) {
+		OF_prop_free(ranges);
+		return (ENXIO);
+	}
+	sc->sc_npins = ranges[3];
+	OF_prop_free(ranges);
+
+	/* Check the number of pins in the DTS vs HW capabilities. */
+	if (sc->sc_npins > sc->sc_max_pins)
+		return (ENXIO);
+
+	err = bus_alloc_resources(dev, a37x0_gpio_res_spec, sc->sc_mem_res);
+	if (err != 0) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+	sc->sc_bst = rman_get_bustag(sc->sc_mem_res[A37X0_GPIO]);
+	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res[A37X0_GPIO]);
+
+	sc->sc_busdev = gpiobus_attach_bus(dev);
+	if (sc->sc_busdev == NULL)
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+a37x0_gpio_detach(device_t dev)
+{
+
+	return (EBUSY);
+}
+
+static device_method_t a37x0_gpio_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		a37x0_gpio_probe),
+	DEVMETHOD(device_attach,	a37x0_gpio_attach),
+	DEVMETHOD(device_detach,	a37x0_gpio_detach),
+
+	/* GPIO interface */
+	DEVMETHOD(gpio_get_bus,		a37x0_gpio_get_bus),
+	DEVMETHOD(gpio_pin_max,		a37x0_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname,	a37x0_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getcaps,	a37x0_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_getflags,	a37x0_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_setflags,	a37x0_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get,		a37x0_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set,		a37x0_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle,	a37x0_gpio_pin_toggle),
+
+	/* ofw_bus interface */
+	DEVMETHOD(ofw_bus_get_node,	a37x0_gpio_get_node),
+
+	DEVMETHOD_END
+};
+
+static devclass_t a37x0_gpio_devclass;
+static driver_t a37x0_gpio_driver = {
+	"gpio",
+	a37x0_gpio_methods,
+	sizeof(struct a37x0_gpio_softc),
+};
+
+EARLY_DRIVER_MODULE(a37x0_gpio, simple_mfd, a37x0_gpio_driver,
+    a37x0_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LAST);

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Mon Jun 10 21:26:14 2019	(r348879)
+++ head/sys/arm64/conf/GENERIC	Mon Jun 10 21:27:21 2019	(r348880)
@@ -223,6 +223,7 @@ device a10_codec
 device		a31_dmac
 
 # GPIO / PINCTRL
+device		a37x0_gpio	# Marvell Armada 37x0 GPIO controller
 device		aw_gpio		# Allwinner GPIO controller
 device		gpio
 device		gpioled

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Mon Jun 10 21:26:14 2019	(r348879)
+++ head/sys/conf/files.arm64	Mon Jun 10 21:27:21 2019	(r348880)
@@ -95,6 +95,7 @@ arm/broadcom/bcm2835/bcm2835_vcio.c		optional soc_brcm
 arm/broadcom/bcm2835/bcm2835_wdog.c		optional soc_brcm_bcm2837 fdt
 arm/broadcom/bcm2835/bcm2836.c			optional soc_brcm_bcm2837 fdt
 arm/broadcom/bcm2835/bcm283x_dwc_fdt.c		optional dwcotg fdt soc_brcm_bcm2837
+arm/mv/a37x0_gpio.c				optional a37x0_gpio gpio fdt
 arm/mv/gpio.c					optional mv_gpio fdt
 arm/mv/mvebu_pinctrl.c				optional mvebu_pinctrl fdt
 arm/mv/mv_cp110_icu.c				optional mv_cp110_icu fdt



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201906102127.x5ALRLt4078623>