Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Aug 2022 19:38:11 +0800
From:      Ganbold Tsagaankhuu <ganbold@gmail.com>
To:        Ganbold Tsagaankhuu <ganbold@freebsd.org>
Cc:        src-committers@freebsd.org, dev-commits-src-all@freebsd.org,  dev-commits-src-main@freebsd.org
Subject:   Re: git: ec556724d7ad - main - Add interrupt handling to rk_gpio driver.
Message-ID:  <CAGtf9xM9gk5TgF9mgKNYO_DLHb_W_ry8a8Adx9T60uo2nLg26w@mail.gmail.com>
In-Reply-To: <202208201132.27KBWQPq086007@gitrepo.freebsd.org>
References:  <202208201132.27KBWQPq086007@gitrepo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
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),
>
>
>

[-- Attachment #2 --]
<div dir="ltr"><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Aug 20, 2022 at 7:32 PM Ganbold Tsagaankhuu &lt;<a href="mailto:ganbold@freebsd.org">ganbold@freebsd.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The branch main has been updated by ganbold:<br>
<br>
URL: <a href="https://cgit.FreeBSD.org/src/commit/?id=ec556724d7ad1ee117fe595728e73dc9ddf78048" rel="noreferrer" target="_blank">https://cgit.FreeBSD.org/src/commit/?id=ec556724d7ad1ee117fe595728e73dc9ddf78048</a><br>;
<br>
commit ec556724d7ad1ee117fe595728e73dc9ddf78048<br>
Author:     Søren Schmidt &lt;sos@FreeBSD.org&gt;<br>
AuthorDate: 2022-08-20 06:09:49 +0000<br>
Commit:     Ganbold Tsagaankhuu &lt;ganbold@FreeBSD.org&gt;<br>
CommitDate: 2022-08-20 11:30:54 +0000<br>
<br>
    Add interrupt handling to rk_gpio driver.<br></blockquote><div><br></div><div>Sorry, it was reviewed by manu and differential revision is <a href="https://reviews.freebsd.org/D36273">https://reviews.freebsd.org/D36273</a></div><div>Probably I missed git arc ... command before pushing.</div><div><br></div><div>Ganbold</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
---<br>
 sys/arm64/rockchip/rk_gpio.c | 227 ++++++++++++++++++++++++++++++++++++++++++-<br>
 1 file changed, 226 insertions(+), 1 deletion(-)<br>
<br>
diff --git a/sys/arm64/rockchip/rk_gpio.c b/sys/arm64/rockchip/rk_gpio.c<br>
index c9ad1c9ea1df..c3b1044df2f7 100644<br>
--- a/sys/arm64/rockchip/rk_gpio.c<br>
+++ b/sys/arm64/rockchip/rk_gpio.c<br>
@@ -36,6 +36,7 @@ __FBSDID(&quot;$FreeBSD$&quot;);<br>
<br>
 #include &lt;sys/kernel.h&gt;<br>
 #include &lt;sys/module.h&gt;<br>
+#include &lt;sys/proc.h&gt;<br>
 #include &lt;sys/rman.h&gt;<br>
 #include &lt;sys/lock.h&gt;<br>
 #include &lt;sys/mutex.h&gt;<br>
@@ -51,6 +52,7 @@ __FBSDID(&quot;$FreeBSD$&quot;);<br>
 #include &lt;dev/extres/clk/clk.h&gt;<br>
<br>
 #include &quot;gpio_if.h&quot;<br>
+#include &quot;pic_if.h&quot;<br>
<br>
 #include &quot;fdt_pinctrl_if.h&quot;<br>
<br>
@@ -73,7 +75,9 @@ enum gpio_regs {<br>
 #define        RK_GPIO_LS_SYNC         0x60    /* Level sensitive syncronization enable register */<br>
<br>
 #define        RK_GPIO_DEFAULT_CAPS    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |     \<br>
-    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)<br>
+    GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN | GPIO_INTR_EDGE_BOTH | \<br>
+    GPIO_INTR_EDGE_RISING | GPIO_INTR_EDGE_FALLING | \<br>
+    GPIO_INTR_LEVEL_HIGH | GPIO_INTR_LEVEL_LOW)<br>
<br>
 #define        GPIO_FLAGS_PINCTRL      GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN<br>
 #define        RK_GPIO_MAX_PINS        32<br>
@@ -83,6 +87,12 @@ struct pin_cached {<br>
        uint32_t        flags;<br>
 };<br>
<br>
+struct rk_pin_irqsrc {<br>
+       struct intr_irqsrc      isrc;<br>
+       uint32_t                irq;<br>
+       uint32_t                mode;<br>
+};<br>
+<br>
 struct rk_gpio_softc {<br>
        device_t                sc_dev;<br>
        device_t                sc_busdev;<br>
@@ -97,6 +107,8 @@ struct rk_gpio_softc {<br>
        uint32_t                version;<br>
        struct pin_cached       pin_cached[RK_GPIO_MAX_PINS];<br>
        uint8_t                 regs[RK_GPIO_REGNUM];<br>
+       void                    *ihandle;<br>
+       struct rk_pin_irqsrc    isrcs[RK_GPIO_MAX_PINS];<br>
 };<br>
<br>
 static struct ofw_compat_data compat_data[] = {<br>
@@ -113,6 +125,7 @@ static struct resource_spec rk_gpio_spec[] = {<br>
 #define        RK_GPIO_VERSION         0x78<br>
 #define        RK_GPIO_TYPE_V1         0x00000000<br>
 #define        RK_GPIO_TYPE_V2         0x01000c2b<br>
+#define        RK_GPIO_ISRC(sc, irq)   (&amp;(sc-&gt;isrcs[irq].isrc))<br>
<br>
 static int rk_gpio_detach(device_t dev);<br>
<br>
@@ -141,6 +154,29 @@ rk_gpio_read_bit(struct rk_gpio_softc *sc, int reg, int bit)<br>
        return (value &amp; 1);<br>
 }<br>
<br>
+static void<br>
+rk_gpio_write_bit(struct rk_gpio_softc *sc, int reg, int bit, int data)<br>
+{<br>
+       int offset = sc-&gt;regs[reg];<br>
+       uint32_t value;<br>
+<br>
+       if (sc-&gt;version == RK_GPIO_TYPE_V1) {<br>
+               value = RK_GPIO_READ(sc, offset);<br>
+               if (data)<br>
+                       value |= (1 &lt;&lt; bit);<br>
+               else<br>
+                       value &amp;= ~(1 &lt;&lt; bit);<br>
+               RK_GPIO_WRITE(sc, offset, value);<br>
+       } else {<br>
+               if (data)<br>
+                       value = (1 &lt;&lt; (bit % 16));<br>
+               else<br>
+                       value = 0;<br>
+               value |= (1 &lt;&lt; ((bit % 16) + 16));<br>
+               RK_GPIO_WRITE(sc, bit &gt; 15 ? offset + 4 : offset, value);<br>
+       }<br>
+}<br>
+<br>
 static uint32_t<br>
 rk_gpio_read_4(struct rk_gpio_softc *sc, int reg)<br>
 {<br>
@@ -168,6 +204,43 @@ rk_gpio_write_4(struct rk_gpio_softc *sc, int reg, uint32_t value)<br>
        }<br>
 }<br>
<br>
+static int<br>
+rk_gpio_intr(void *arg)<br>
+{<br>
+       struct rk_gpio_softc *sc = (struct rk_gpio_softc *)arg;;<br>
+       struct trapframe *tf = curthread-&gt;td_intr_frame;<br>
+       uint32_t status;<br>
+<br>
+       RK_GPIO_LOCK(sc);<br>
+       status = rk_gpio_read_4(sc, RK_GPIO_INT_STATUS);<br>
+       rk_gpio_write_4(sc, RK_GPIO_PORTA_EOI, status);<br>
+       RK_GPIO_UNLOCK(sc);<br>
+<br>
+       while (status) {<br>
+               int pin = ffs(status) - 1;<br>
+<br>
+               status &amp;= ~(1 &lt;&lt; pin);<br>
+               if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) {<br>
+                       device_printf(sc-&gt;sc_dev, &quot;Interrupt pin=%d unhandled\n&quot;,<br>
+                           pin);<br>
+                       continue;<br>
+               }<br>
+<br>
+               if ((sc-&gt;version == RK_GPIO_TYPE_V1) &amp;&amp;<br>
+                   (sc-&gt;isrcs[pin].mode &amp; GPIO_INTR_EDGE_BOTH)) {<br>
+                       RK_GPIO_LOCK(sc);<br>
+                       if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))<br>
+                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,<br>
+                                   (1 &lt;&lt; pin), 0);<br>
+                       else<br>
+                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,<br>
+                                   (1 &lt;&lt; pin), 1);<br>
+                       RK_GPIO_UNLOCK(sc);<br>
+               }<br>
+       }<br>
+       return (FILTER_HANDLED);<br>
+}<br>
+<br>
 static int<br>
 rk_gpio_probe(device_t dev)<br>
 {<br>
@@ -221,6 +294,15 @@ rk_gpio_attach(device_t dev)<br>
                rk_gpio_detach(dev);<br>
                return (ENXIO);<br>
        }<br>
+<br>
+       if ((err = bus_setup_intr(dev, sc-&gt;sc_res[1],<br>
+           INTR_TYPE_MISC | INTR_MPSAFE, rk_gpio_intr, NULL,<br>
+           sc, &amp;sc-&gt;ihandle))) {<br>
+               device_printf(dev, &quot;Can not setup IRQ\n&quot;);<br>
+               rk_gpio_detach(dev);<br>
+               return (ENXIO);<br>
+       }<br>
+<br>
        RK_GPIO_LOCK(sc);<br>
        sc-&gt;version = rk_gpio_read_4(sc, RK_GPIO_VERSION);<br>
        RK_GPIO_UNLOCK(sc);<br>
@@ -259,6 +341,23 @@ rk_gpio_attach(device_t dev)<br>
                return (ENXIO);<br>
        }<br>
<br>
+       for (i = 0; i &lt; RK_GPIO_MAX_PINS; i++) {<br>
+               sc-&gt;isrcs[i].irq = i;<br>
+               sc-&gt;isrcs[i].mode = GPIO_INTR_CONFORM;<br>
+               if ((err = intr_isrc_register(RK_GPIO_ISRC(sc, i),<br>
+                   dev, 0, &quot;%s&quot;, device_get_nameunit(dev)))) {<br>
+                       device_printf(dev, &quot;Can not register isrc %d\n&quot;, err);<br>
+                       rk_gpio_detach(dev);<br>
+                       return (ENXIO);<br>
+               }<br>
+       }<br>
+<br>
+       if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) {<br>
+               device_printf(dev, &quot;Can not register pic\n&quot;);<br>
+               rk_gpio_detach(dev);<br>
+               return (ENXIO);<br>
+       }<br>
+<br>
        sc-&gt;sc_busdev = gpiobus_attach_bus(dev);<br>
        if (sc-&gt;sc_busdev == NULL) {<br>
                rk_gpio_detach(dev);<br>
@@ -549,6 +648,127 @@ rk_gpio_get_node(device_t bus, device_t dev)<br>
        return (ofw_bus_get_node(bus));<br>
 }<br>
<br>
+static int<br>
+rk_pic_map_intr(device_t dev, struct intr_map_data *data,<br>
+    struct intr_irqsrc **isrcp)<br>
+{<br>
+       struct rk_gpio_softc *sc = device_get_softc(dev);<br>
+       struct intr_map_data_gpio *gdata;<br>
+       uint32_t irq;<br>
+<br>
+       if (data-&gt;type != INTR_MAP_DATA_GPIO) {<br>
+               device_printf(dev, &quot;Wrong type\n&quot;);<br>
+               return (ENOTSUP);<br>
+       }<br>
+       gdata = (struct intr_map_data_gpio *)data;<br>
+       irq = gdata-&gt;gpio_pin_num;<br>
+       if (irq &gt;= RK_GPIO_MAX_PINS) {<br>
+               device_printf(dev, &quot;Invalid interrupt %u\n&quot;, irq);<br>
+               return (EINVAL);<br>
+       }<br>
+       *isrcp = RK_GPIO_ISRC(sc, irq);<br>
+       return (0);<br>
+}<br>
+<br>
+static int<br>
+rk_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,<br>
+    struct resource *res, struct intr_map_data *data)<br>
+{<br>
+       struct rk_gpio_softc *sc = device_get_softc(dev);<br>
+       struct rk_pin_irqsrc *rkisrc = (struct rk_pin_irqsrc *)isrc;<br>
+       struct intr_map_data_gpio *gdata;<br>
+       uint32_t mode;<br>
+       uint8_t pin;<br>
+<br>
+       if (!data) {<br>
+               device_printf(dev, &quot;No map data\n&quot;);<br>
+               return (ENOTSUP);<br>
+       }<br>
+       gdata = (struct intr_map_data_gpio *)data;<br>
+       mode = gdata-&gt;gpio_intr_mode;<br>
+       pin = gdata-&gt;gpio_pin_num;<br>
+<br>
+       if (rkisrc-&gt;irq != gdata-&gt;gpio_pin_num) {<br>
+               device_printf(dev, &quot;Interrupts don&#39;t match\n&quot;);<br>
+               return (EINVAL);<br>
+       }<br>
+<br>
+       if (isrc-&gt;isrc_handlers != 0) {<br>
+               device_printf(dev, &quot;Handler already attached\n&quot;);<br>
+               return (rkisrc-&gt;mode == mode ? 0 : EINVAL);<br>
+       }<br>
+       rkisrc-&gt;mode = mode;<br>
+<br>
+       RK_GPIO_LOCK(sc);<br>
+<br>
+       switch (mode &amp; GPIO_INTR_MASK) {<br>
+       case GPIO_INTR_EDGE_RISING:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);<br>
+               break;<br>
+       case GPIO_INTR_EDGE_FALLING:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);<br>
+               break;<br>
+       case GPIO_INTR_EDGE_BOTH:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 1);<br>
+               if (sc-&gt;version == RK_GPIO_TYPE_V1) {<br>
+                       if (rk_gpio_read_bit(sc, RK_GPIO_EXT_PORTA, pin))<br>
+                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,<br>
+                                   pin, 0);<br>
+                       else<br>
+                               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,<br>
+                                   pin, 1);<br>
+               } else<br>
+                       rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_BOTH, pin, 1);<br>
+               break;<br>
+       case GPIO_INTR_LEVEL_HIGH:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 1);<br>
+               break;<br>
+       case GPIO_INTR_LEVEL_LOW:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_SWPORTA_DDR, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTTYPE_LEVEL, pin, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY, pin, 0);<br>
+               break;<br>
+       default:<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 1);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 0);<br>
+               RK_GPIO_UNLOCK(sc);<br>
+               return (EINVAL);<br>
+       }<br>
+       rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, pin, 1);<br>
+       rk_gpio_write_bit(sc, RK_GPIO_INTMASK, pin, 0);<br>
+       rk_gpio_write_bit(sc, RK_GPIO_INTEN, pin, 1);<br>
+       RK_GPIO_UNLOCK(sc);<br>
+<br>
+       return (0);<br>
+}<br>
+<br>
+static int<br>
+rk_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,<br>
+    struct resource *res, struct intr_map_data *data)<br>
+{<br>
+       struct rk_gpio_softc *sc = device_get_softc(dev);<br>
+       struct rk_pin_irqsrc *irqsrc;<br>
+<br>
+       irqsrc = (struct rk_pin_irqsrc *)isrc;<br>
+<br>
+       if (isrc-&gt;isrc_handlers == 0) {<br>
+               irqsrc-&gt;mode = GPIO_INTR_CONFORM;<br>
+               RK_GPIO_LOCK(sc);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTEN, irqsrc-&gt;irq, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_INTMASK, irqsrc-&gt;irq, 0);<br>
+               rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, irqsrc-&gt;irq, 0);<br>
+               RK_GPIO_UNLOCK(sc);<br>
+       }<br>
+       return (0);<br>
+}<br>
+<br>
 static device_method_t rk_gpio_methods[] = {<br>
        /* Device interface */<br>
        DEVMETHOD(device_probe,         rk_gpio_probe),<br>
@@ -569,6 +789,11 @@ static device_method_t rk_gpio_methods[] = {<br>
        DEVMETHOD(gpio_pin_config_32,   rk_gpio_pin_config_32),<br>
        DEVMETHOD(gpio_map_gpios,       rk_gpio_map_gpios),<br>
<br>
+       /* Interrupt controller interface */<br>
+       DEVMETHOD(pic_map_intr,         rk_pic_map_intr),<br>
+       DEVMETHOD(pic_setup_intr,       rk_pic_setup_intr),<br>
+       DEVMETHOD(pic_teardown_intr,    rk_pic_teardown_intr),<br>
+<br>
        /* ofw_bus interface */<br>
        DEVMETHOD(ofw_bus_get_node,     rk_gpio_get_node),<br>
<br>
<br>
</blockquote></div></div>

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