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
 };
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to