From nobody Sat Aug 20 11:32:26 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4M8xLL57fwz4Z4lx; Sat, 20 Aug 2022 11:32:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4M8xLL4bv8z45Xm; Sat, 20 Aug 2022 11:32:26 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1660995146; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=75/LkfOrfFKcSS+2y4wq7ZMZ4vjgvPe712pVGas+B5Q=; b=DjSzFbr5+7j0AwHwkX+hhCbAxafhKOQp3Ww7Ld8dseSk61WxRfGbPKombZget8Rvf/ps6z k1DbkMuIqo4APdjMncmnDtyxGc1FZH1E8ejZOx6Lb95OW0PDek8yz32Ia/ay7TLBR42U+b HZ+y+n+s+NBpviQodRmc4amhgoBvlKMYY0cSd25WgyV9mQq/Aq83d033hFH/ueRQOLUoZi ZgoXXJSzf80K6isZwWT3Qjykf9UTq+cQFzDgj32HqKmRtcYoMdDbAHZlJ8eRjNs0eJLfFq AAKKYUs0ON2RGXHF8JytbNssjIaYZsodKbTYPwvOyZNog0SpYLndhQClDR7I3w== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4M8xLL3fhpzW58; Sat, 20 Aug 2022 11:32:26 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 27KBWQXK086017; Sat, 20 Aug 2022 11:32:26 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 27KBWQPq086007; Sat, 20 Aug 2022 11:32:26 GMT (envelope-from git) Date: Sat, 20 Aug 2022 11:32:26 GMT Message-Id: <202208201132.27KBWQPq086007@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Ganbold Tsagaankhuu Subject: git: ec556724d7ad - main - Add interrupt handling to rk_gpio driver. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: ganbold X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: ec556724d7ad1ee117fe595728e73dc9ddf78048 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1660995146; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=75/LkfOrfFKcSS+2y4wq7ZMZ4vjgvPe712pVGas+B5Q=; b=ufYV4YUrl6Rhx6cvt/LemkCSe66kb1yEeZn1W9dn/5p6TOkQeqHux8esDzHfoGomUrP/hY 4OGRmzjnhEfwaPa0K2NwVRykm9Er+jdmlBDZ66Ixl1YjFIQipWjEs6jF2iXQtl2FfoUEwA vGuE/r4Sk6h3Chb6YF5lli2PejVWy4kdyFpq6l9qILkt327bhz7433QCrSRSUA2aZy1k+4 i+GR3uH4NAZqobu5dxeqJw4LbTBamy6yX7f6KvR7q+7mON3MTjeaLtAK8hNTQc23fads3q Nd4s+SEUCxlsPIry6AS1wSCjLZ3erY1823vDqjeF7eFk8NdkP9jvNK1MY7bjWw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1660995146; a=rsa-sha256; cv=none; b=HK91CUr/JV1/iQLHi/hPFggub9WBSOd7oPyogCFx9au27OrL0fehYIlddxiMG9Ym43Y9wc r6aVdYMobWLZl9YN1VJ0ca3vHGAbFXvuOPW2d5vHfRwi1oi5gHfuY8J8dSOMjHUycyyEBs CxbO0rSWuTgQke16UdOk3gzZM4y7M9HRr3kg8ZakiiMrDM9iJr1FnT2zBiqu9+kUVJI7ni Eq+pdVVyIF0qPRNtxV3+Yd/V9Gv3XdNo1Wcn4ZWiylCxFEORS6RKmx8bK34Umy6uu4ur/g uh3L39gleu9UIgQ0GwwdsFF+QMSA08oidK6QETUWytTuBZn7EcOiHt0aND08Jg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by ganbold: URL: https://cgit.FreeBSD.org/src/commit/?id=ec556724d7ad1ee117fe595728e73dc9ddf78048 commit ec556724d7ad1ee117fe595728e73dc9ddf78048 Author: Søren Schmidt AuthorDate: 2022-08-20 06:09:49 +0000 Commit: Ganbold Tsagaankhuu CommitDate: 2022-08-20 11:30:54 +0000 Add interrupt handling to rk_gpio driver. --- 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 #include +#include #include #include #include @@ -51,6 +52,7 @@ __FBSDID("$FreeBSD$"); #include #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),