Loongson 1A's INT controller support two different interrupt trigger mode: level trigger and edge trigger. Whether the INT controller stores the external interrupts is the difference between them. The edge trigger should do this, and operate INT_CLR register to clear the CPU interrupt state. Signed-off-by: Chunbo Cui <cuicb@xxxxxxxxxx> Signed-off-by: Binbin Zhou <zhoubb@xxxxxxxxxx> Signed-off-by: Huacai Chen <chenhc@xxxxxxxxxx> --- arch/mips/loongson32/common/irq.c | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/arch/mips/loongson32/common/irq.c b/arch/mips/loongson32/common/irq.c index 455a770..76dd185 100644 --- a/arch/mips/loongson32/common/irq.c +++ b/arch/mips/loongson32/common/irq.c @@ -62,12 +62,57 @@ static void ls1x_irq_unmask(struct irq_data *d) | (1 << bit), LS1X_INTC_INTIEN(n)); } +static int ls1x_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; + unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; + + if (flow_type & IRQ_TYPE_EDGE_BOTH) { + if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + pr_info("ls1x irq don't support both rising and falling\n"); + return -1; + } + ls1x_writel(ls1x_readl(LS1X_INTC_INTCLR(n)) + | (1 << bit), LS1X_INTC_INTCLR(n)); + if (flow_type & IRQ_TYPE_EDGE_RISING) + ls1x_writel(ls1x_readl(LS1X_INTC_INTPOL(n)) + | (1 << bit), LS1X_INTC_INTPOL(n)); + else + ls1x_writel(ls1x_readl(LS1X_INTC_INTPOL(n)) + & ~(1 << bit), LS1X_INTC_INTPOL(n)); + + ls1x_writel(ls1x_readl(LS1X_INTC_INTEDGE(n)) + | (1 << bit), LS1X_INTC_INTEDGE(n)); + ls1x_writel(ls1x_readl(LS1X_INTC_INTIEN(n)) + | (1 << bit), LS1X_INTC_INTIEN(n)); + __irq_set_handler_locked(d->irq, handle_edge_irq); + } else if (flow_type && IRQ_TYPE_LEVEL_MASK) { + ls1x_writel(ls1x_readl(LS1X_INTC_INTCLR(n)) + | (1 << bit), LS1X_INTC_INTCLR(n)); + if (flow_type & IRQ_TYPE_LEVEL_HIGH) + ls1x_writel(ls1x_readl(LS1X_INTC_INTPOL(n)) + | (1 << bit), LS1X_INTC_INTPOL(n)); + else if (flow_type & IRQ_TYPE_LEVEL_LOW) + ls1x_writel(ls1x_readl(LS1X_INTC_INTPOL(n)) + & ~(1 << bit), LS1X_INTC_INTPOL(n)); + + ls1x_writel(ls1x_readl(LS1X_INTC_INTEDGE(n)) + & ~(1 << bit), LS1X_INTC_INTEDGE(n)); + ls1x_writel(ls1x_readl(LS1X_INTC_INTIEN(n)) + | (1 << bit), LS1X_INTC_INTIEN(n)); + __irq_set_handler_locked(d->irq, handle_level_irq); + } + + return IRQ_SET_MASK_OK; +} + static struct irq_chip ls1x_irq_chip = { .name = "LS1X-INTC", .irq_ack = ls1x_irq_ack, .irq_mask = ls1x_irq_mask, .irq_mask_ack = ls1x_irq_mask_ack, .irq_unmask = ls1x_irq_unmask, + .irq_set_type = ls1x_irq_set_type, }; static void ls1x_irq_dispatch(int n) @@ -138,6 +183,7 @@ static void __init ls1x_irq_init(int base) setup_irq(INT1_IRQ, &cascade_irqaction); setup_irq(INT2_IRQ, &cascade_irqaction); setup_irq(INT3_IRQ, &cascade_irqaction); + setup_irq(INT4_IRQ, &cascade_irqaction); } void __init arch_init_irq(void) -- 1.9.0