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
This commit is contained in:
parent
f97f57b518
commit
a5dce53b75
@ -83,9 +83,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#define MV_GPIO_MAX_NIRQS 4
|
#define MV_GPIO_MAX_NIRQS 4
|
||||||
#define MV_GPIO_MAX_NPINS 32
|
#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 mvebu_gpio_irqsrc {
|
||||||
struct intr_irqsrc isrc;
|
struct intr_irqsrc isrc;
|
||||||
u_int irq;
|
u_int irq;
|
||||||
@ -127,14 +124,11 @@ static inline void
|
|||||||
gpio_write(struct mvebu_gpio_softc *sc, bus_size_t reg,
|
gpio_write(struct mvebu_gpio_softc *sc, bus_size_t reg,
|
||||||
struct gpio_pin *pin, uint32_t val)
|
struct gpio_pin *pin, uint32_t val)
|
||||||
{
|
{
|
||||||
uint32_t tmp;
|
|
||||||
int bit;
|
int bit;
|
||||||
|
|
||||||
bit = GPIO_BIT(pin->gp_pin);
|
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,
|
SYSCON_WRITE_4(sc->syscon, sc->offset + GPIO_REGNUM(pin->gp_pin) + reg,
|
||||||
tmp);
|
(val & 1) << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t
|
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);
|
bit = GPIO_BIT(pin->gp_pin);
|
||||||
val = SYSCON_READ_4(sc->syscon,
|
val = SYSCON_READ_4(sc->syscon,
|
||||||
sc->offset + GPIO_REGNUM(pin->gp_pin) + reg);
|
sc->offset + GPIO_REGNUM(pin->gp_pin) + reg);
|
||||||
|
|
||||||
return (val >> bit) & 1;
|
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
|
static void
|
||||||
mvebu_gpio_pin_configure(struct mvebu_gpio_softc *sc, struct gpio_pin *pin,
|
mvebu_gpio_pin_configure(struct mvebu_gpio_softc *sc, struct gpio_pin *pin,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
@ -305,15 +311,14 @@ mvebu_gpio_pin_toggle(device_t dev, uint32_t pin)
|
|||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
intr_modify(struct mvebu_gpio_softc *sc, bus_addr_t reg,
|
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;
|
int bit;
|
||||||
|
|
||||||
bit = GPIO_BIT(mgi->irq);
|
bit = GPIO_BIT(mgi->irq);
|
||||||
GPIO_LOCK(sc);
|
SYSCON_MODIFY_4(sc->syscon,
|
||||||
val = SYSCON_MODIFY_4(sc->syscon,
|
sc->offset + GPIO_REGNUM(mgi->irq) + reg, 1 << bit,
|
||||||
sc->offset + GPIO_REGNUM(mgi->irq) + reg, val, mask);
|
(val & 1) << bit);
|
||||||
GPIO_UNLOCK(sc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -322,18 +327,23 @@ mvebu_gpio_isrc_mask(struct mvebu_gpio_softc *sc,
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (mgi->is_level)
|
if (mgi->is_level)
|
||||||
intr_modify(sc, GPIO_INT_LEVEL_MASK, mgi, val, 1);
|
intr_modify(sc, GPIO_INT_LEVEL_MASK, mgi, val);
|
||||||
else
|
else
|
||||||
intr_modify(sc, GPIO_INT_MASK, mgi, val, 1);
|
intr_modify(sc, GPIO_INT_MASK, mgi, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
mvebu_gpio_isrc_eoi(struct mvebu_gpio_softc *sc,
|
mvebu_gpio_isrc_eoi(struct mvebu_gpio_softc *sc,
|
||||||
struct mvebu_gpio_irqsrc *mgi)
|
struct mvebu_gpio_irqsrc *mgi)
|
||||||
{
|
{
|
||||||
|
int bit;
|
||||||
|
|
||||||
if (!mgi->is_level)
|
if (!mgi->is_level) {
|
||||||
intr_modify(sc, GPIO_INT_CAUSE, mgi, 0, 1);
|
bit = GPIO_BIT(mgi->irq);
|
||||||
|
SYSCON_WRITE_4(sc->syscon,
|
||||||
|
sc->offset + GPIO_REGNUM(mgi->irq) + GPIO_INT_CAUSE,
|
||||||
|
~(1 << bit));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -596,8 +606,11 @@ mvebu_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
|
|||||||
|
|
||||||
mgi->is_level = level;
|
mgi->is_level = level;
|
||||||
mgi->is_inverted = inverted;
|
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);
|
mvebu_gpio_pic_enable_intr(dev, isrc);
|
||||||
|
GPIO_UNLOCK(sc);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -641,12 +654,13 @@ mvebu_gpio_intr(void *arg)
|
|||||||
lvl &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &sc->gpio_pins[i]);
|
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_DATA_IN, &sc->gpio_pins[i]);
|
||||||
edge &= gpio_read(sc, GPIO_INT_LEVEL_MASK, &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;
|
continue;
|
||||||
|
|
||||||
mgi = &sc->isrcs[i];
|
mgi = &sc->isrcs[i];
|
||||||
if (!mgi->is_level)
|
if (!mgi->is_level)
|
||||||
mvebu_gpio_isrc_eoi(sc, mgi);
|
mvebu_gpio_isrc_eoi(sc, mgi);
|
||||||
|
|
||||||
if (intr_isrc_dispatch(&mgi->isrc, tf) != 0) {
|
if (intr_isrc_dispatch(&mgi->isrc, tf) != 0) {
|
||||||
mvebu_gpio_isrc_mask(sc, mgi, 0);
|
mvebu_gpio_isrc_mask(sc, mgi, 0);
|
||||||
if (mgi->is_level)
|
if (mgi->is_level)
|
||||||
@ -776,11 +790,11 @@ mvebu_gpio_attach(device_t dev)
|
|||||||
snprintf(pin->gp_name, GPIOMAXNAME, "gpio%d", i);
|
snprintf(pin->gp_name, GPIOMAXNAME, "gpio%d", i);
|
||||||
|
|
||||||
/* Init HW */
|
/* Init HW */
|
||||||
gpio_write(sc, GPIO_INT_MASK, pin, 0);
|
gpio_modify(sc, GPIO_INT_MASK, pin, 0);
|
||||||
gpio_write(sc, GPIO_INT_LEVEL_MASK, pin, 0);
|
gpio_modify(sc, GPIO_INT_LEVEL_MASK, pin, 0);
|
||||||
gpio_write(sc, GPIO_INT_CAUSE, pin, 0);
|
gpio_modify(sc, GPIO_INT_CAUSE, pin, 0);
|
||||||
gpio_write(sc, GPIO_DATA_IN_POL, pin, 1);
|
gpio_modify(sc, GPIO_DATA_IN_POL, pin, 0);
|
||||||
gpio_write(sc, GPIO_BLINK_ENA, pin, 0);
|
gpio_modify(sc, GPIO_BLINK_ENA, pin, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sc->irq_res[0] != NULL) {
|
if (sc->irq_res[0] != NULL) {
|
||||||
|
Loading…
Reference in New Issue
Block a user