git: 9ddb35ef1fd2 - stable/13 - mvebu_gpio: Multiple fixes.

From: Michal Meloun <mmel_at_FreeBSD.org>
Date: Thu, 20 Jan 2022 10:24:08 UTC
The branch stable/13 has been updated by mmel:

URL: https://cgit.FreeBSD.org/src/commit/?id=9ddb35ef1fd2870ebb0e4cd9a6772f32991735f0

commit 9ddb35ef1fd2870ebb0e4cd9a6772f32991735f0
Author:     Michal Meloun <mmel@FreeBSD.org>
AuthorDate: 2021-03-03 17:28:45 +0000
Commit:     Michal Meloun <mmel@FreeBSD.org>
CommitDate: 2022-01-20 10:22:04 +0000

    mvebu_gpio: Multiple fixes.
    
    - gpio register access primitives
    - locking in interrupt path
    - cleanup
    
    In cooperation with: mw
    Reviewed by:    mw (initial version)
    MFC after:      3 weeks
    Differential Revision:  https://reviews.freebsd.org/D29044
    Differential Revision:  https://reviews.freebsd.org/D28911
    
    (cherry picked from commit a5dce53b75d8750ba95623ad2dbffac4acfd3545)
---
 sys/arm/mv/mvebu_gpio.c | 60 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/sys/arm/mv/mvebu_gpio.c b/sys/arm/mv/mvebu_gpio.c
index f0471b8d019c..c38fbceebf24 100644
--- a/sys/arm/mv/mvebu_gpio.c
+++ b/sys/arm/mv/mvebu_gpio.c
@@ -83,9 +83,6 @@ __FBSDID("$FreeBSD$");
 #define	MV_GPIO_MAX_NIRQS	4
 #define	MV_GPIO_MAX_NPINS	32
 
-#define	RD4(sc, reg)		SYSCON_READ_4((sc)->syscon, (reg))
-#define	WR4(sc, reg, val)	SYSCON_WRITE_4((sc)->syscon, (reg), (val))
-
 struct mvebu_gpio_irqsrc {
 	struct intr_irqsrc	isrc;
 	u_int			irq;
@@ -127,14 +124,11 @@ static inline void
 gpio_write(struct mvebu_gpio_softc *sc, bus_size_t reg,
     struct gpio_pin *pin, uint32_t val)
 {
-	uint32_t tmp;
 	int bit;
 
 	bit = GPIO_BIT(pin->gp_pin);
-	tmp = 0x100 << bit;		/* mask */
-	tmp |= (val & 1) << bit;	/* value */
 	SYSCON_WRITE_4(sc->syscon, sc->offset + GPIO_REGNUM(pin->gp_pin) + reg,
-	    tmp);
+	    (val & 1) << bit);
 }
 
 static inline uint32_t
@@ -146,9 +140,21 @@ gpio_read(struct mvebu_gpio_softc *sc, bus_size_t reg, struct gpio_pin *pin)
 	bit = GPIO_BIT(pin->gp_pin);
 	val = SYSCON_READ_4(sc->syscon,
 	    sc->offset + GPIO_REGNUM(pin->gp_pin) + reg);
+
 	return (val >> bit) & 1;
 }
 
+static inline void
+gpio_modify(struct mvebu_gpio_softc *sc, bus_size_t reg,
+    struct gpio_pin *pin, uint32_t val)
+{
+	int bit;
+
+	bit = GPIO_BIT(pin->gp_pin);
+	SYSCON_MODIFY_4(sc->syscon, sc->offset + GPIO_REGNUM(pin->gp_pin) + reg,
+	    1 << bit, (val & 1) << bit);
+}
+
 static void
 mvebu_gpio_pin_configure(struct mvebu_gpio_softc *sc, struct gpio_pin *pin,
     unsigned int flags)
@@ -305,15 +311,14 @@ mvebu_gpio_pin_toggle(device_t dev, uint32_t pin)
  */
 static inline void
 intr_modify(struct mvebu_gpio_softc *sc, bus_addr_t reg,
-    struct mvebu_gpio_irqsrc *mgi, uint32_t val, uint32_t mask)
+    struct mvebu_gpio_irqsrc *mgi, uint32_t val)
 {
 	int bit;
 
 	bit = GPIO_BIT(mgi->irq);
-	GPIO_LOCK(sc);
-	val = SYSCON_MODIFY_4(sc->syscon,
-	    sc->offset + GPIO_REGNUM(mgi->irq) + reg, val, mask);
-	GPIO_UNLOCK(sc);
+	SYSCON_MODIFY_4(sc->syscon,
+	    sc->offset + GPIO_REGNUM(mgi->irq) + reg, 1 << bit,
+	    (val & 1) << bit);
 }
 
 static inline void
@@ -322,18 +327,23 @@ mvebu_gpio_isrc_mask(struct mvebu_gpio_softc *sc,
 {
 
 	if (mgi->is_level)
-		intr_modify(sc, GPIO_INT_LEVEL_MASK, mgi, val, 1);
+		intr_modify(sc, GPIO_INT_LEVEL_MASK, mgi, val);
 	else
-		intr_modify(sc, GPIO_INT_MASK, mgi, val, 1);
+		intr_modify(sc, GPIO_INT_MASK, mgi, val);
 }
 
 static inline void
 mvebu_gpio_isrc_eoi(struct mvebu_gpio_softc *sc,
      struct mvebu_gpio_irqsrc *mgi)
 {
+	int bit;
 
-	if (!mgi->is_level)
-		intr_modify(sc, GPIO_INT_CAUSE, mgi, 0, 1);
+	if (!mgi->is_level) {
+		bit = GPIO_BIT(mgi->irq);
+		SYSCON_WRITE_4(sc->syscon,
+		    sc->offset + GPIO_REGNUM(mgi->irq) + GPIO_INT_CAUSE,
+		    ~(1 << bit));
+	}
 }
 
 static int
@@ -596,8 +606,11 @@ mvebu_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
 
 	mgi->is_level = level;
 	mgi->is_inverted = inverted;
-	intr_modify(sc, GPIO_DATA_IN_POL, mgi, inverted ? 1 : 0, 1);
+
+	GPIO_LOCK(sc);
+	intr_modify(sc, GPIO_DATA_IN_POL, mgi, inverted ? 1 : 0);
 	mvebu_gpio_pic_enable_intr(dev, isrc);
+	GPIO_UNLOCK(sc);
 
 	return (0);
 }
@@ -641,12 +654,13 @@ mvebu_gpio_intr(void *arg)
 		lvl &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &sc->gpio_pins[i]);
 		edge = gpio_read(sc, GPIO_DATA_IN, &sc->gpio_pins[i]);
 		edge &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &sc->gpio_pins[i]);
-		if (edge == 0  || lvl == 0)
+		if (edge == 0  && lvl == 0)
 			continue;
 
 		mgi = &sc->isrcs[i];
 		if (!mgi->is_level)
 			mvebu_gpio_isrc_eoi(sc, mgi);
+
 		if (intr_isrc_dispatch(&mgi->isrc, tf) != 0) {
 			mvebu_gpio_isrc_mask(sc, mgi, 0);
 			if (mgi->is_level)
@@ -776,11 +790,11 @@ mvebu_gpio_attach(device_t dev)
 		snprintf(pin->gp_name, GPIOMAXNAME, "gpio%d", i);
 
 		/* Init HW */
-		gpio_write(sc, GPIO_INT_MASK, pin, 0);
-		gpio_write(sc, GPIO_INT_LEVEL_MASK, pin, 0);
-		gpio_write(sc, GPIO_INT_CAUSE, pin, 0);
-		gpio_write(sc, GPIO_DATA_IN_POL, pin, 1);
-		gpio_write(sc, GPIO_BLINK_ENA, pin, 0);
+		gpio_modify(sc, GPIO_INT_MASK, pin, 0);
+		gpio_modify(sc, GPIO_INT_LEVEL_MASK, pin, 0);
+		gpio_modify(sc, GPIO_INT_CAUSE, pin, 0);
+		gpio_modify(sc, GPIO_DATA_IN_POL, pin, 0);
+		gpio_modify(sc, GPIO_BLINK_ENA, pin, 0);
 	}
 
 	if (sc->irq_res[0] != NULL) {