Re: git: ec556724d7ad - main - Add interrupt handling to rk_gpio driver.

From: Ganbold Tsagaankhuu <ganbold_at_gmail.com>
Date: Sat, 20 Aug 2022 11:38:11 UTC
On Sat, Aug 20, 2022 at 7:32 PM Ganbold Tsagaankhuu <ganbold@freebsd.org>
wrote:

> The branch main has been updated by ganbold:
>
> URL:
> https://cgit.FreeBSD.org/src/commit/?id=ec556724d7ad1ee117fe595728e73dc9ddf78048
>
> commit ec556724d7ad1ee117fe595728e73dc9ddf78048
> Author:     Søren Schmidt <sos@FreeBSD.org>
> AuthorDate: 2022-08-20 06:09:49 +0000
> Commit:     Ganbold Tsagaankhuu <ganbold@FreeBSD.org>
> CommitDate: 2022-08-20 11:30:54 +0000
>
>     Add interrupt handling to rk_gpio driver.
>

Sorry, it was reviewed by manu and differential revision is
https://reviews.freebsd.org/D36273
Probably I missed git arc ... command before pushing.

Ganbold


> ---
>  sys/arm64/rockchip/rk_gpio.c | 227
> ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 226 insertions(+), 1 deletion(-)
>
> diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c
> index c9ad1c9ea1df..c3b1044df2f7 100644
> --- a/sys/arm64/rockchip/rk_gpio.c
> +++ b/sys/arm64/rockchip/rk_gpio.c
> @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
>
>  #include <sys/kernel.h>
>  #include <sys/module.h>
> +#include <sys/proc.h>
>  #include <sys/rman.h>
>  #include <sys/lock.h>
>  #include <sys/mutex.h>
> @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$");
>  #include <dev/extres/clk/clk.h>
>
>  #include "gpio_if.h"
> +#include "pic_if.h"
>
>  #include "fdt_pinctrl_if.h"
>
> @@ -73,7 +75,9 @@ enum gpio_regs {
>  #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)
> +    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_EDGE_BOTH | \
> +    GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | \
> +    GPIO_INTR_LEVEL_HIGH | GPIO_INTR_LEVEL_LOW)
>
>  #define        GPIO_FLAGS_PINCTRL      GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN
>  #define        RK_GPIO_MAX_PINS        32
> @@ -83,6 +87,12 @@ struct pin_cached {
>         uint32_t        flags;
>  };
>
> +struct rk_pin_irqsrc {
> +       struct intr_irqsrc      isrc;
> +       uint32_t                irq;
> +       uint32_t                mode;
> +};
> +
>  struct rk_gpio_softc {
>         device_t                sc_dev;
>         device_t                sc_busdev;
> @@ -97,6 +107,8 @@ struct rk_gpio_softc {
>         uint32_t                version;
>         struct pin_cached       pin_cached[RK_GPIO_MAX_PINS];
>         uint8_t                 regs[RK_GPIO_REGNUM];
> +       void                    *ihandle;
> +       struct rk_pin_irqsrc    isrcs[RK_GPIO_MAX_PINS];
>  };
>
>  static struct ofw_compat_data compat_data[] = {
> @@ -113,6 +125,7 @@ static struct resource_spec rk_gpio_spec[] = {
>  #define        RK_GPIO_VERSION         0x78
>  #define        RK_GPIO_TYPE_V1         0x00000000
>  #define        RK_GPIO_TYPE_V2         0x01000c2b
> +#define        RK_GPIO_ISRC(sc, irq)   (&(sc->isrcs[irq].isrc))
>
>  static int rk_gpio_detach(device_t dev);
>
> @@ -141,6 +154,29 @@ rk_gpio_read_bit(struct rk_gpio_softc *sc, int reg,
> int bit)
>         return (value & 1);
>  }
>
> +static void
> +rk_gpio_write_bit(struct rk_gpio_softc *sc, int reg, int bit, int data)
> +{
> +       int offset = sc->regs[reg];
> +       uint32_t value;
> +
> +       if (sc->version == RK_GPIO_TYPE_V1) {
> +               value = RK_GPIO_READ(sc, offset);
> +               if (data)
> +                       value |= (1 << bit);
> +               else
> +                       value &= ~(1 << bit);
> +               RK_GPIO_WRITE(sc, offset, value);
> +       } else {
> +               if (data)
> +                       value = (1 << (bit % 16));
> +               else
> +                       value = 0;
> +               value |= (1 << ((bit % 16) + 16));
> +               RK_GPIO_WRITE(sc, bit > 15 ? offset + 4 : offset, value);
> +       }
> +}
> +
>  static uint32_t
>  rk_gpio_read_4(struct rk_gpio_softc *sc, int reg)
>  {
> @@ -168,6 +204,43 @@ rk_gpio_write_4(struct rk_gpio_softc *sc, int reg,
> uint32_t value)
>         }
>  }
>
> +static int
> +rk_gpio_intr(void *arg)
> +{
> +       struct rk_gpio_softc *sc = (struct rk_gpio_softc *)arg;;
> +       struct trapframe *tf = curthread->td_intr_frame;
> +       uint32_t status;
> +
> +       RK_GPIO_LOCK(sc);
> +       status = rk_gpio_read_4(sc, RK_GPIO_INT_STATUS);
> +       rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, status);
> +       RK_GPIO_UNLOCK(sc);
> +
> +       while (status) {
> +               int pin = ffs(status) - 1;
> +
> +               status &= ~(1 << pin);
> +               if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) {
> +                       device_printf(sc->sc_dev, "Interrupt pin=%d
> unhandled\n",
> +                           pin);
> +                       continue;
> +               }
> +
> +               if ((sc->version == RK_GPIO_TYPE_V1) &&
> +                   (sc->isrcs[pin].mode & GPIO_INTR_EDGE_BOTH)) {
> +                       RK_GPIO_LOCK(sc);
> +                       if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))
> +                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
> +                                   (1 << pin), 0);
> +                       else
> +                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
> +                                   (1 << pin), 1);
> +                       RK_GPIO_UNLOCK(sc);
> +               }
> +       }
> +       return (FILTER_HANDLED);
> +}
> +
>  static int
>  rk_gpio_probe(device_t dev)
>  {
> @@ -221,6 +294,15 @@ rk_gpio_attach(device_t dev)
>                 rk_gpio_detach(dev);
>                 return (ENXIO);
>         }
> +
> +       if ((err = bus_setup_intr(dev, sc->sc_res[1],
> +           INTR_TYPE_MISC | INTR_MPSAFE, rk_gpio_intr, NULL,
> +           sc, &sc->ihandle))) {
> +               device_printf(dev, "Can not setup IRQ\n");
> +               rk_gpio_detach(dev);
> +               return (ENXIO);
> +       }
> +
>         RK_GPIO_LOCK(sc);
>         sc->version = rk_gpio_read_4(sc, RK_GPIO_VERSION);
>         RK_GPIO_UNLOCK(sc);
> @@ -259,6 +341,23 @@ rk_gpio_attach(device_t dev)
>                 return (ENXIO);
>         }
>
> +       for (i = 0; i < RK_GPIO_MAX_PINS; i++) {
> +               sc->isrcs[i].irq = i;
> +               sc->isrcs[i].mode = GPIO_INTR_CONFORM;
> +               if ((err = intr_isrc_register(RK_GPIO_ISRC(sc, i),
> +                   dev, 0, "%s", device_get_nameunit(dev)))) {
> +                       device_printf(dev, "Can not register isrc %d\n",
> err);
> +                       rk_gpio_detach(dev);
> +                       return (ENXIO);
> +               }
> +       }
> +
> +       if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {
> +               device_printf(dev, "Can not register pic\n");
> +               rk_gpio_detach(dev);
> +               return (ENXIO);
> +       }
> +
>         sc->sc_busdev = gpiobus_attach_bus(dev);
>         if (sc->sc_busdev == NULL) {
>                 rk_gpio_detach(dev);
> @@ -549,6 +648,127 @@ rk_gpio_get_node(device_t bus, device_t dev)
>         return (ofw_bus_get_node(bus));
>  }
>
> +static int
> +rk_pic_map_intr(device_t dev, struct intr_map_data *data,
> +    struct intr_irqsrc **isrcp)
> +{
> +       struct rk_gpio_softc *sc = device_get_softc(dev);
> +       struct intr_map_data_gpio *gdata;
> +       uint32_t irq;
> +
> +       if (data->type != INTR_MAP_DATA_GPIO) {
> +               device_printf(dev, "Wrong type\n");
> +               return (ENOTSUP);
> +       }
> +       gdata = (struct intr_map_data_gpio *)data;
> +       irq = gdata->gpio_pin_num;
> +       if (irq >= RK_GPIO_MAX_PINS) {
> +               device_printf(dev, "Invalid interrupt %u\n", irq);
> +               return (EINVAL);
> +       }
> +       *isrcp = RK_GPIO_ISRC(sc, irq);
> +       return (0);
> +}
> +
> +static int
> +rk_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
> +    struct resource *res, struct intr_map_data *data)
> +{
> +       struct rk_gpio_softc *sc = device_get_softc(dev);
> +       struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;
> +       struct intr_map_data_gpio *gdata;
> +       uint32_t mode;
> +       uint8_t pin;
> +
> +       if (!data) {
> +               device_printf(dev, "No map data\n");
> +               return (ENOTSUP);
> +       }
> +       gdata = (struct intr_map_data_gpio *)data;
> +       mode = gdata->gpio_intr_mode;
> +       pin = gdata->gpio_pin_num;
> +
> +       if (rkisrc->irq != gdata->gpio_pin_num) {
> +               device_printf(dev, "Interrupts don't match\n");
> +               return (EINVAL);
> +       }
> +
> +       if (isrc->isrc_handlers != 0) {
> +               device_printf(dev, "Handler already attached\n");
> +               return (rkisrc->mode == mode ? 0 : EINVAL);
> +       }
> +       rkisrc->mode = mode;
> +
> +       RK_GPIO_LOCK(sc);
> +
> +       switch (mode & GPIO_INTR_MASK) {
> +       case GPIO_INTR_EDGE_RISING:
> +               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
> +               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);
> +               break;
> +       case GPIO_INTR_EDGE_FALLING:
> +               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
> +               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);
> +               break;
> +       case GPIO_INTR_EDGE_BOTH:
> +               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);
> +               if (sc->version == RK_GPIO_TYPE_V1) {
> +                       if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))
> +                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
> +                                   pin, 0);
> +                       else
> +                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,
> +                                   pin, 1);
> +               } else
> +                       rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_BOTH, pin,
> 1);
> +               break;
> +       case GPIO_INTR_LEVEL_HIGH:
> +               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);
> +               break;
> +       case GPIO_INTR_LEVEL_LOW:
> +               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);
> +               break;
> +       default:
> +               rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 1);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 0);
> +               RK_GPIO_UNLOCK(sc);
> +               return (EINVAL);
> +       }
> +       rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, pin, 1);
> +       rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 0);
> +       rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 1);
> +       RK_GPIO_UNLOCK(sc);
> +
> +       return (0);
> +}
> +
> +static int
> +rk_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
> +    struct resource *res, struct intr_map_data *data)
> +{
> +       struct rk_gpio_softc *sc = device_get_softc(dev);
> +       struct rk_pin_irqsrc *irqsrc;
> +
> +       irqsrc = (struct rk_pin_irqsrc *)isrc;
> +
> +       if (isrc->isrc_handlers == 0) {
> +               irqsrc->mode = GPIO_INTR_CONFORM;
> +               RK_GPIO_LOCK(sc);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTEN, irqsrc->irq, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_INTMASK, irqsrc->irq, 0);
> +               rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, irqsrc->irq, 0);
> +               RK_GPIO_UNLOCK(sc);
> +       }
> +       return (0);
> +}
> +
>  static device_method_t rk_gpio_methods[] = {
>         /* Device interface */
>         DEVMETHOD(device_probe,         rk_gpio_probe),
> @@ -569,6 +789,11 @@ static device_method_t rk_gpio_methods[] = {
>         DEVMETHOD(gpio_pin_config_32,   rk_gpio_pin_config_32),
>         DEVMETHOD(gpio_map_gpios,       rk_gpio_map_gpios),
>
> +       /* Interrupt controller interface */
> +       DEVMETHOD(pic_map_intr,         rk_pic_map_intr),
> +       DEVMETHOD(pic_setup_intr,       rk_pic_setup_intr),
> +       DEVMETHOD(pic_teardown_intr,    rk_pic_teardown_intr),
> +
>         /* ofw_bus interface */
>         DEVMETHOD(ofw_bus_get_node,     rk_gpio_get_node),
>
>
>