aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2021-03-03 17:28:45 +0000
committerMichal Meloun <mmel@FreeBSD.org>2021-03-04 16:54:40 +0000
commita5dce53b75d8750ba95623ad2dbffac4acfd3545 (patch)
tree3a2d3b370065881478f6ce606b18df88f0f5e450
parentf97f57b51855cecb9b497a90dfed06dac2c21111 (diff)
downloadsrc-a5dce53b75d8750ba95623ad2dbffac4acfd3545.tar.gz
src-a5dce53b75d8750ba95623ad2dbffac4acfd3545.zip
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
-rw-r--r--sys/arm/mv/mvebu_gpio.c60
1 files 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) {