Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jan 2020 21:21:20 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r356807 - head/sys/arm64/rockchip
Message-ID:  <202001162121.00GLLKqj040172@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Thu Jan 16 21:21:20 2020
New Revision: 356807
URL: https://svnweb.freebsd.org/changeset/base/356807

Log:
  arm64: rockchip: Add new interface for rk_pinctrl
  
  The gpio controller in rockchips SoC in a child of the pinctrl driver
  and cannot control pullups and pulldowns.
  Use the new fdt_pinctrl interface for accessing pin capabilities and
  setting them.
  We can now report that every pins is capable of being IN or OUT function
  and PULLUP PULLDOWN.
  If the pin isn't in gpio mode no changes will be allowed.
  
  Reviewed by:	ganbold (previous version)
  MFC after:	1 month
  Differential Revision:	https://reviews.freebsd.org/D22849

Modified:
  head/sys/arm64/rockchip/rk_gpio.c
  head/sys/arm64/rockchip/rk_pinctrl.c

Modified: head/sys/arm64/rockchip/rk_gpio.c
==============================================================================
--- head/sys/arm64/rockchip/rk_gpio.c	Thu Jan 16 21:19:27 2020	(r356806)
+++ head/sys/arm64/rockchip/rk_gpio.c	Thu Jan 16 21:21:20 2020	(r356807)
@@ -51,6 +51,8 @@ __FBSDID("$FreeBSD$");
 
 #include "gpio_if.h"
 
+#include "fdt_pinctrl_if.h"
+
 #define	RK_GPIO_SWPORTA_DR	0x00	/* Data register */
 #define	RK_GPIO_SWPORTA_DDR	0x04	/* Data direction register */
 
@@ -68,6 +70,9 @@ __FBSDID("$FreeBSD$");
 
 #define	RK_GPIO_LS_SYNC		0x60	/* Level sensitive syncronization enable register */
 
+#define	RK_GPIO_DEFAULT_CAPS	(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |	\
+    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)
+
 struct rk_gpio_softc {
 	device_t		sc_dev;
 	device_t		sc_busdev;
@@ -76,6 +81,7 @@ struct rk_gpio_softc {
 	bus_space_tag_t		sc_bst;
 	bus_space_handle_t	sc_bsh;
 	clk_t			clk;
+	device_t		pinctrl;
 };
 
 static struct ofw_compat_data compat_data[] = {
@@ -123,6 +129,7 @@ rk_gpio_attach(device_t dev)
 
 	sc = device_get_softc(dev);
 	sc->sc_dev = dev;
+	sc->pinctrl = device_get_parent(dev);
 
 	node = ofw_bus_get_node(sc->sc_dev);
 	if (!OF_hasprop(node, "gpio-controller"))
@@ -220,18 +227,30 @@ rk_gpio_pin_getflags(device_t dev, uint32_t pin, uint3
 {
 	struct rk_gpio_softc *sc;
 	uint32_t reg;
+	int rv;
+	bool is_gpio;
 
 	sc = device_get_softc(dev);
 
-	/* XXX Combine this with parent (pinctrl) */
+	rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, &is_gpio);
+	if (rv != 0)
+		return (rv);
+	if (!is_gpio)
+		return (EINVAL);
+
+	*flags = 0;
+	rv = FDT_PINCTRL_GET_FLAGS(sc->pinctrl, dev, pin, flags);
+	if (rv != 0)
+		return (rv);
+
 	RK_GPIO_LOCK(sc);
 	reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR);
 	RK_GPIO_UNLOCK(sc);
 
 	if (reg & (1 << pin))
-		*flags = GPIO_PIN_OUTPUT;
+		*flags |= GPIO_PIN_OUTPUT;
 	else
-		*flags = GPIO_PIN_INPUT;
+		*flags |= GPIO_PIN_INPUT;
 
 	return (0);
 }
@@ -240,9 +259,7 @@ static int
 rk_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
 {
 
-	/* Caps are managed by the pinctrl device */
-	/* XXX Pass this to parent (pinctrl) */
-	*caps = 0;
+	*caps = RK_GPIO_DEFAULT_CAPS;
 	return (0);
 }
 
@@ -251,10 +268,21 @@ rk_gpio_pin_setflags(device_t dev, uint32_t pin, uint3
 {
 	struct rk_gpio_softc *sc;
 	uint32_t reg;
+	int rv;
+	bool is_gpio;
 
 	sc = device_get_softc(dev);
 
-	/* XXX Combine this with parent (pinctrl) */
+	rv = FDT_PINCTRL_IS_GPIO(sc->pinctrl, dev, pin, &is_gpio);
+	if (rv != 0)
+		return (rv);
+	if (!is_gpio)
+		return (EINVAL);
+
+	rv = FDT_PINCTRL_SET_FLAGS(sc->pinctrl, dev, pin, flags);
+	if (rv != 0)
+		return (rv);
+
 	RK_GPIO_LOCK(sc);
 
 	reg = RK_GPIO_READ(sc, RK_GPIO_SWPORTA_DDR);

Modified: head/sys/arm64/rockchip/rk_pinctrl.c
==============================================================================
--- head/sys/arm64/rockchip/rk_pinctrl.c	Thu Jan 16 21:19:27 2020	(r356806)
+++ head/sys/arm64/rockchip/rk_pinctrl.c	Thu Jan 16 21:21:20 2020	(r356807)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 
 #include "gpio_if.h"
 #include "syscon_if.h"
+#include "fdt_pinctrl_if.h"
 
 struct rk_pinctrl_pin_drive {
 	uint32_t	bank;
@@ -101,6 +102,8 @@ struct rk_pinctrl_conf {
 	uint32_t	(*get_pd_offset)(struct rk_pinctrl_softc *, uint32_t);
 	struct syscon	*(*get_syscon)(struct rk_pinctrl_softc *, uint32_t);
 	int		(*parse_bias)(phandle_t, int);
+	int		(*resolv_bias_value)(int, int);
+	int		(*get_bias_value)(int, int);
 };
 
 struct rk_pinctrl_softc {
@@ -109,8 +112,13 @@ struct rk_pinctrl_softc {
 	struct syscon		*grf;
 	struct syscon		*pmu;
 	struct rk_pinctrl_conf	*conf;
+	struct mtx		mtx;
 };
 
+#define	RK_PINCTRL_LOCK(_sc)		mtx_lock_spin(&(_sc)->mtx)
+#define	RK_PINCTRL_UNLOCK(_sc)		mtx_unlock_spin(&(_sc)->mtx)
+#define	RK_PINCTRL_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED)
+
 #define	RK_IOMUX(_bank, _subbank, _offset, _nbits)			\
 {									\
 	.bank = _bank,							\
@@ -384,6 +392,32 @@ rk3288_parse_bias(phandle_t node, int bank)
 	return (-1);
 }
 
+static int
+rk3288_resolv_bias_value(int bank, int bias)
+{
+	int rv = 0;
+
+	if (bias == 1)
+		rv = GPIO_PIN_PULLUP;
+	else if (bias == 2)
+		rv = GPIO_PIN_PULLDOWN;
+
+	return (rv);
+}
+
+static int
+rk3288_get_bias_value(int bank, int bias)
+{
+	int rv = 0;
+
+	if (bias & GPIO_PIN_PULLUP)
+		rv = 1;
+	else if (bias & GPIO_PIN_PULLDOWN)
+		rv = 2;
+
+	return (rv);
+}
+
 struct rk_pinctrl_conf rk3288_conf = {
 	.iomux_conf = rk3288_iomux_bank,
 	.iomux_nbanks = nitems(rk3288_iomux_bank),
@@ -396,6 +430,8 @@ struct rk_pinctrl_conf rk3288_conf = {
 	.get_pd_offset = rk3288_get_pd_offset,
 	.get_syscon = rk3288_get_syscon,
 	.parse_bias = rk3288_parse_bias,
+	.resolv_bias_value = rk3288_resolv_bias_value,
+	.get_bias_value = rk3288_get_bias_value,
 };
 
 static struct rk_pinctrl_gpio rk3328_gpio_bank[] = {
@@ -540,6 +576,8 @@ struct rk_pinctrl_conf rk3328_conf = {
 	.get_pd_offset = rk3328_get_pd_offset,
 	.get_syscon = rk3328_get_syscon,
 	.parse_bias = rk3288_parse_bias,
+	.resolv_bias_value = rk3288_resolv_bias_value,
+	.get_bias_value = rk3288_get_bias_value,
 };
 
 static struct rk_pinctrl_gpio rk3399_gpio_bank[] = {
@@ -663,6 +701,58 @@ rk3399_parse_bias(phandle_t node, int bank)
 	return (-1);
 }
 
+static int
+rk3399_resolv_bias_value(int bank, int bias)
+{
+	int rv = 0;
+
+	switch (bank) {
+	case 0:
+	case 2:
+		if (bias == 3)
+			rv = GPIO_PIN_PULLUP;
+		else if (bias == 1)
+			rv = GPIO_PIN_PULLDOWN;
+		break;
+	case 1:
+	case 3:
+	case 4:
+		if (bias == 1)
+			rv = GPIO_PIN_PULLUP;
+		else if (bias == 2)
+			rv = GPIO_PIN_PULLDOWN;
+		break;
+	}
+
+	return (rv);
+}
+
+static int
+rk3399_get_bias_value(int bank, int bias)
+{
+	int rv = 0;
+
+	switch (bank) {
+	case 0:
+	case 2:
+		if (bias & GPIO_PIN_PULLUP)
+			rv = 3;
+		else if (bias & GPIO_PIN_PULLDOWN)
+			rv = 1;
+		break;
+	case 1:
+	case 3:
+	case 4:
+		if (bias & GPIO_PIN_PULLUP)
+			rv = 1;
+		else if (bias & GPIO_PIN_PULLDOWN)
+			rv = 2;
+		break;
+	}
+
+	return (rv);
+}
+
 struct rk_pinctrl_conf rk3399_conf = {
 	.iomux_conf = rk3399_iomux_bank,
 	.iomux_nbanks = nitems(rk3399_iomux_bank),
@@ -675,6 +765,8 @@ struct rk_pinctrl_conf rk3399_conf = {
 	.get_pd_offset = rk3399_get_pd_offset,
 	.get_syscon = rk3399_get_syscon,
 	.parse_bias = rk3399_parse_bias,
+	.resolv_bias_value = rk3399_resolv_bias_value,
+	.get_bias_value = rk3399_get_bias_value,
 };
 
 static struct ofw_compat_data compat_data[] = {
@@ -920,8 +1012,189 @@ rk_pinctrl_configure_pins(device_t dev, phandle_t cfgx
 	return (0);
 }
 
+static int
+rk_pinctrl_is_gpio_locked(struct rk_pinctrl_softc *sc, struct syscon *syscon,
+  int bank, uint32_t pin, bool *is_gpio)
+{
+	uint32_t subbank, bit, mask, reg;
+	uint32_t pinfunc;
+	int i;
 
+	RK_PINCTRL_LOCK_ASSERT(sc);
+
+	subbank = pin / 8;
+	*is_gpio = false;
+
+	for (i = 0; i < sc->conf->iomux_nbanks; i++)
+		if (sc->conf->iomux_conf[i].bank == bank &&
+		    sc->conf->iomux_conf[i].subbank == subbank)
+			break;
+
+	if (i == sc->conf->iomux_nbanks) {
+		device_printf(sc->dev, "Unknown pin %d in bank %d\n", pin,
+		    bank);
+		return (EINVAL);
+	}
+
+	syscon = sc->conf->get_syscon(sc, bank);
+
+	/* Parse pin function */
+	reg = sc->conf->iomux_conf[i].offset;
+	switch (sc->conf->iomux_conf[i].nbits) {
+	case 4:
+		if ((pin % 8) >= 4)
+			reg += 0x4;
+		bit = (pin % 4) * 4;
+		mask = (0xF << bit);
+		break;
+	case 3:
+		if ((pin % 8) >= 5)
+			reg += 4;
+		bit = (pin % 8 % 5) * 3;
+		mask = (0x7 << bit);
+		break;
+	case 2:
+		bit = (pin % 8) * 2;
+		mask = (0x3 << bit);
+		break;
+	default:
+		device_printf(sc->dev,
+		    "Unknown pin stride width %d in bank %d\n",
+		    sc->conf->iomux_conf[i].nbits, bank);
+		return (EINVAL);
+	}
+	rk_pinctrl_get_fixup(sc, bank, pin, &reg, &mask, &bit);
+
+	reg = SYSCON_READ_4(syscon, reg);
+	pinfunc = (reg & mask) >> bit;
+
+	/* Test if the pin is in gpio mode */
+	if (pinfunc == 0)
+		*is_gpio = true;
+
+	return (0);
+}
+
 static int
+rk_pinctrl_get_bank(struct rk_pinctrl_softc *sc, device_t gpio, int *bank)
+{
+	int i;
+
+	for (i = 0; i < sc->conf->ngpio_bank; i++) {
+		if (sc->conf->gpio_bank[i].gpio_dev == gpio)
+			break;
+	}
+	if (i == sc->conf->ngpio_bank)
+		return (EINVAL);
+
+	*bank = i;
+	return (0);
+}
+
+static int
+rk_pinctrl_is_gpio(device_t pinctrl, device_t gpio, uint32_t pin, bool *is_gpio)
+{
+	struct rk_pinctrl_softc *sc;
+	struct syscon *syscon;
+	int bank;
+	int rv;
+
+	sc = device_get_softc(pinctrl);
+	RK_PINCTRL_LOCK(sc);
+
+	rv = rk_pinctrl_get_bank(sc, gpio, &bank);
+	if (rv != 0)
+		goto done;
+	syscon = sc->conf->get_syscon(sc, bank);
+	rv = rk_pinctrl_is_gpio_locked(sc, syscon, bank, pin, is_gpio);
+
+done:
+	RK_PINCTRL_UNLOCK(sc);
+
+	return (rv);
+}
+
+static int
+rk_pinctrl_get_flags(device_t pinctrl, device_t gpio, uint32_t pin,
+    uint32_t *flags)
+{
+	struct rk_pinctrl_softc *sc;
+	struct syscon *syscon;
+	uint32_t reg, mask, bit;
+	uint32_t bias;
+	int bank;
+	int rv = 0;
+	bool is_gpio;
+
+	sc = device_get_softc(pinctrl);
+	RK_PINCTRL_LOCK(sc);
+
+	rv = rk_pinctrl_get_bank(sc, gpio, &bank);
+	if (rv != 0)
+		goto done;
+	syscon = sc->conf->get_syscon(sc, bank);
+	rv = rk_pinctrl_is_gpio_locked(sc, syscon, bank, pin, &is_gpio);
+	if (rv != 0)
+		goto done;
+	if (!is_gpio) {
+		rv = EINVAL;
+		goto done;
+	}
+	/* Get the pullup/pulldown configuration */
+	reg = sc->conf->get_pd_offset(sc, bank);
+	reg += bank * 0x10 + ((pin / 8) * 0x4);
+	bit = (pin % 8) * 2;
+	mask = (0x3 << bit) << 16;
+	reg = SYSCON_READ_4(syscon, reg);
+	reg = (reg >> bit) & 0x3;
+	bias = sc->conf->resolv_bias_value(bank, reg);
+	*flags = bias;
+
+done:
+	RK_PINCTRL_UNLOCK(sc);
+	return (rv);
+}
+
+static int
+rk_pinctrl_set_flags(device_t pinctrl, device_t gpio, uint32_t pin,
+    uint32_t flags)
+{
+	struct rk_pinctrl_softc *sc;
+	struct syscon *syscon;
+	uint32_t bit, mask, reg;
+	uint32_t bias;
+	int bank;
+	int rv = 0;
+	bool is_gpio;
+
+	sc = device_get_softc(pinctrl);
+	RK_PINCTRL_LOCK(sc);
+
+	rv = rk_pinctrl_get_bank(sc, gpio, &bank);
+	if (rv != 0)
+		goto done;
+	syscon = sc->conf->get_syscon(sc, bank);
+	rv = rk_pinctrl_is_gpio_locked(sc, syscon, bank, pin, &is_gpio);
+	if (rv != 0)
+		goto done;
+	if (!is_gpio) {
+		rv = EINVAL;
+		goto done;
+	}
+	/* Get the pullup/pulldown configuration */
+	reg = sc->conf->get_pd_offset(sc, bank);
+	reg += bank * 0x10 + ((pin / 8) * 0x4);
+	bit = (pin % 8) * 2;
+	mask = (0x3 << bit);
+	bias = sc->conf->get_bias_value(bank, flags);
+	SYSCON_MODIFY_4(syscon, reg, mask, bias << bit | (mask << 16));
+
+done:
+	RK_PINCTRL_UNLOCK(sc);
+	return (rv);
+}
+
+static int
 rk_pinctrl_register_gpio(struct rk_pinctrl_softc *sc, char *gpio_name,
     device_t gpio_dev)
 {
@@ -982,6 +1255,8 @@ rk_pinctrl_attach(device_t dev)
 		}
 	}
 
+	mtx_init(&sc->mtx, "rk pinctrl", "pinctrl", MTX_SPIN);
+
 	sc->conf = (struct rk_pinctrl_conf *)ofw_bus_search_compatible(dev,
 	    compat_data)->ocd_data;
 
@@ -1059,6 +1334,9 @@ static device_method_t rk_pinctrl_methods[] = {
 
         /* fdt_pinctrl interface */
 	DEVMETHOD(fdt_pinctrl_configure,	rk_pinctrl_configure_pins),
+	DEVMETHOD(fdt_pinctrl_is_gpio,		rk_pinctrl_is_gpio),
+	DEVMETHOD(fdt_pinctrl_get_flags,	rk_pinctrl_get_flags),
+	DEVMETHOD(fdt_pinctrl_set_flags,	rk_pinctrl_set_flags),
 
 	DEVMETHOD_END
 };



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