|
|
|
@ -1,5 +1,6 @@ |
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> |
|
|
|
|
* Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> |
|
|
|
|
* |
|
|
|
|
* This file is subject to the terms and conditions of the GNU General Public |
|
|
|
|
* License. See the file "COPYING" in the main directory of this archive |
|
|
|
@ -20,15 +21,38 @@ |
|
|
|
|
#include <asm/irq.h> |
|
|
|
|
#include <adm8668.h> |
|
|
|
|
|
|
|
|
|
/* interrupt controller */ |
|
|
|
|
#define IRQ_STATUS_REG 0x00 /* Read */ |
|
|
|
|
#define IRQ_ENABLE_REG 0x08 /* Read/Write */ |
|
|
|
|
#define IRQ_DISABLE_REG 0x0C /* Write */ |
|
|
|
|
|
|
|
|
|
#define IRQ_MASK 0xffff |
|
|
|
|
|
|
|
|
|
static inline void intc_write_reg(u32 val, unsigned int reg) |
|
|
|
|
{ |
|
|
|
|
void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); |
|
|
|
|
|
|
|
|
|
__raw_writel(val, base + reg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static inline u32 intc_read_reg(unsigned int reg) |
|
|
|
|
{ |
|
|
|
|
void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); |
|
|
|
|
|
|
|
|
|
return __raw_readl(base + reg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void adm8668_irq_cascade(void) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
unsigned long intsrc; |
|
|
|
|
int irq; |
|
|
|
|
u32 intsrc; |
|
|
|
|
|
|
|
|
|
intsrc = ADM8668_INTC_REG(IRQ_STATUS_REG) & IRQ_MASK; |
|
|
|
|
for (i = 0; intsrc; intsrc >>= 1, i++) |
|
|
|
|
if (intsrc & 0x1) |
|
|
|
|
do_IRQ(i); |
|
|
|
|
intsrc = intc_read_reg(IRQ_STATUS_REG) & IRQ_MASK; |
|
|
|
|
if (intsrc) { |
|
|
|
|
irq = fls(intsrc) - 1; |
|
|
|
|
do_IRQ(irq); |
|
|
|
|
} else |
|
|
|
|
spurious_interrupt(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -43,8 +67,10 @@ void plat_irq_dispatch(void) |
|
|
|
|
/* timer interrupt, that we renumbered */ |
|
|
|
|
if (pending & STATUSF_IP7) |
|
|
|
|
do_IRQ(MIPS_CPU_IRQ_BASE + 7); |
|
|
|
|
if (pending & STATUSF_IP2) |
|
|
|
|
else if (pending & STATUSF_IP2) |
|
|
|
|
adm8668_irq_cascade(); |
|
|
|
|
else |
|
|
|
|
spurious_interrupt(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -52,13 +78,13 @@ void plat_irq_dispatch(void) |
|
|
|
|
*/ |
|
|
|
|
static void enable_adm8668_irq(struct irq_data *d) |
|
|
|
|
{ |
|
|
|
|
ADM8668_INTC_REG(IRQ_ENABLE_REG) = (1 << d->irq); |
|
|
|
|
intc_write_reg((1 << d->irq), IRQ_ENABLE_REG); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void ack_adm8668_irq(struct irq_data *d) |
|
|
|
|
{ |
|
|
|
|
ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << d->irq); |
|
|
|
|
intc_write_reg((1 << d->irq), IRQ_DISABLE_REG); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -79,6 +105,9 @@ static void __init init_adm8668_irqs(void) |
|
|
|
|
{ |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
/* disable all interrupts for the moment */ |
|
|
|
|
intc_write_reg(IRQ_MASK, IRQ_DISABLE_REG); |
|
|
|
|
|
|
|
|
|
for (i = 0; i <= INT_LVL_MAX; i++) |
|
|
|
|
irq_set_chip_and_handler(i, &adm8668_irq_type, |
|
|
|
|
handle_level_irq); |
|
|
|
|