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 <<a href="mailto:ganbold@freebsd.org">ganbold@freebsd.org</a>> 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 <sos@FreeBSD.org><br> AuthorDate: 2022-08-20 06:09:49 +0000<br> Commit: Ganbold Tsagaankhuu <ganbold@FreeBSD.org><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("$FreeBSD$");<br> <br> #include <sys/kernel.h><br> #include <sys/module.h><br> +#include <sys/proc.h><br> #include <sys/rman.h><br> #include <sys/lock.h><br> #include <sys/mutex.h><br> @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$");<br> #include <dev/extres/clk/clk.h><br> <br> #include "gpio_if.h"<br> +#include "pic_if.h"<br> <br> #include "fdt_pinctrl_if.h"<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) (&(sc->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 & 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->regs[reg];<br> + uint32_t value;<br> +<br> + if (sc->version == RK_GPIO_TYPE_V1) {<br> + value = RK_GPIO_READ(sc, offset);<br> + if (data)<br> + value |= (1 << bit);<br> + else<br> + value &= ~(1 << bit);<br> + RK_GPIO_WRITE(sc, offset, value);<br> + } else {<br> + if (data)<br> + value = (1 << (bit % 16));<br> + else<br> + value = 0;<br> + value |= (1 << ((bit % 16) + 16));<br> + RK_GPIO_WRITE(sc, bit > 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->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 &= ~(1 << pin);<br> + if (intr_isrc_dispatch(RK_GPIO_ISRC(sc, pin), tf)) {<br> + device_printf(sc->sc_dev, "Interrupt pin=%d unhandled\n",<br> + pin);<br> + continue;<br> + }<br> +<br> + if ((sc->version == RK_GPIO_TYPE_V1) &&<br> + (sc->isrcs[pin].mode & 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 << pin), 0);<br> + else<br> + rk_gpio_write_bit(sc, RK_GPIO_INT_POLARITY,<br> + (1 << 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->sc_res[1],<br> + INTR_TYPE_MISC | INTR_MPSAFE, rk_gpio_intr, NULL,<br> + sc, &sc->ihandle))) {<br> + device_printf(dev, "Can not setup IRQ\n");<br> + rk_gpio_detach(dev);<br> + return (ENXIO);<br> + }<br> +<br> RK_GPIO_LOCK(sc);<br> sc->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 < RK_GPIO_MAX_PINS; i++) {<br> + sc->isrcs[i].irq = i;<br> + sc->isrcs[i].mode = GPIO_INTR_CONFORM;<br> + if ((err = intr_isrc_register(RK_GPIO_ISRC(sc, i),<br> + dev, 0, "%s", device_get_nameunit(dev)))) {<br> + device_printf(dev, "Can not register isrc %d\n", 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, "Can not register pic\n");<br> + rk_gpio_detach(dev);<br> + return (ENXIO);<br> + }<br> +<br> sc->sc_busdev = gpiobus_attach_bus(dev);<br> if (sc->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->type != INTR_MAP_DATA_GPIO) {<br> + device_printf(dev, "Wrong type\n");<br> + return (ENOTSUP);<br> + }<br> + gdata = (struct intr_map_data_gpio *)data;<br> + irq = gdata->gpio_pin_num;<br> + if (irq >= RK_GPIO_MAX_PINS) {<br> + device_printf(dev, "Invalid interrupt %u\n", 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, "No map data\n");<br> + return (ENOTSUP);<br> + }<br> + gdata = (struct intr_map_data_gpio *)data;<br> + mode = gdata->gpio_intr_mode;<br> + pin = gdata->gpio_pin_num;<br> +<br> + if (rkisrc->irq != gdata->gpio_pin_num) {<br> + device_printf(dev, "Interrupts don't match\n");<br> + return (EINVAL);<br> + }<br> +<br> + if (isrc->isrc_handlers != 0) {<br> + device_printf(dev, "Handler already attached\n");<br> + return (rkisrc->mode == mode ? 0 : EINVAL);<br> + }<br> + rkisrc->mode = mode;<br> +<br> + RK_GPIO_LOCK(sc);<br> +<br> + switch (mode & 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->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->isrc_handlers == 0) {<br> + irqsrc->mode = GPIO_INTR_CONFORM;<br> + RK_GPIO_LOCK(sc);<br> + rk_gpio_write_bit(sc, RK_GPIO_INTEN, irqsrc->irq, 0);<br> + rk_gpio_write_bit(sc, RK_GPIO_INTMASK, irqsrc->irq, 0);<br> + rk_gpio_write_bit(sc, RK_GPIO_DEBOUNCE, irqsrc->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>
