From nobody Sat Aug 20 11:32:26 2022
X-Original-To: dev-commits-src-main@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 <ganbold@FreeBSD.org>
Subject: git: ec556724d7ad - main - Add interrupt handling to rk_gpio driver.
List-Id: Commit messages for the main branch of the src repository <dev-commits-src-main.freebsd.org>
List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main
List-Help: <mailto:dev-commits-src-main+help@freebsd.org>
List-Post: <mailto:dev-commits-src-main@freebsd.org>
List-Subscribe: <mailto:dev-commits-src-main+subscribe@freebsd.org>
List-Unsubscribe: <mailto:dev-commits-src-main+unsubscribe@freebsd.org>
Sender: owner-dev-commits-src-main@freebsd.org
X-BeenThere: dev-commits-src-main@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 <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.
---
 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),