sh: intc - convert voyagergx code
This patch converts the sh-specific voyagergx interrupt code to make use of intc. A lot of "interesting" old cruft gets replaced with intc tables and some simple demux code. - All interrupt sources in the sm501 data sheet are now in the header. - The number and order of IRQ values are disconnected from register bits. - Interrupt sources now start from IRQ 200. - set_irq_chained_handler() is now used to hook up the demux function. In the future it would probably make sense to move the interrupt demuxer into into the mfd driver, but this is probably a nice step in the right direction until that happens. Tested on a R2D-1 board using the serial port hooked up to the sm501. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
parent
51da64264b
commit
48180cab3a
4 changed files with 96 additions and 144 deletions
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <asm/voyagergx.h>
|
||||||
#include <asm/rts7751r2d.h>
|
#include <asm/rts7751r2d.h>
|
||||||
|
|
||||||
#if defined(CONFIG_RTS7751R2D_REV11)
|
#if defined(CONFIG_RTS7751R2D_REV11)
|
||||||
|
@ -21,9 +22,6 @@ static int mask_pos[] = {11, 9, 8, 12, 10, 6, 5, 4, 7, 14, 13, 0, 0, 0, 0};
|
||||||
static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
|
static int mask_pos[] = {6, 11, 9, 8, 12, 10, 5, 4, 7, 14, 13, 0, 0, 0, 0};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int voyagergx_irq_demux(int irq);
|
|
||||||
extern void setup_voyagergx_irq(void);
|
|
||||||
|
|
||||||
static void enable_rts7751r2d_irq(unsigned int irq)
|
static void enable_rts7751r2d_irq(unsigned int irq)
|
||||||
{
|
{
|
||||||
/* Set priority in IPR back to original value */
|
/* Set priority in IPR back to original value */
|
||||||
|
@ -39,7 +37,7 @@ static void disable_rts7751r2d_irq(unsigned int irq)
|
||||||
|
|
||||||
int rts7751r2d_irq_demux(int irq)
|
int rts7751r2d_irq_demux(int irq)
|
||||||
{
|
{
|
||||||
return voyagergx_irq_demux(irq);
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_chip rts7751r2d_irq_chip __read_mostly = {
|
static struct irq_chip rts7751r2d_irq_chip __read_mostly = {
|
||||||
|
|
|
@ -82,7 +82,7 @@ static struct plat_serial8250_port uart_platform_data[] = {
|
||||||
.membase = (void __iomem *)VOYAGER_UART_BASE,
|
.membase = (void __iomem *)VOYAGER_UART_BASE,
|
||||||
.mapbase = VOYAGER_UART_BASE,
|
.mapbase = VOYAGER_UART_BASE,
|
||||||
.iotype = UPIO_MEM,
|
.iotype = UPIO_MEM,
|
||||||
.irq = VOYAGER_UART0_IRQ,
|
.irq = IRQ_SM501_U0,
|
||||||
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
|
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
|
||||||
.regshift = 2,
|
.regshift = 2,
|
||||||
.uartclk = (9600 * 16),
|
.uartclk = (9600 * 16),
|
||||||
|
@ -125,7 +125,7 @@ static struct resource sm501_resources[] = {
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_MEM,
|
||||||
},
|
},
|
||||||
[2] = {
|
[2] = {
|
||||||
.start = 32,
|
.start = IRQ_SM501_CV,
|
||||||
.flags = IORESOURCE_IRQ,
|
.flags = IORESOURCE_IRQ,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -187,7 +187,6 @@ static void __init rts7751r2d_setup(char **cmdline_p)
|
||||||
static struct sh_machine_vector mv_rts7751r2d __initmv = {
|
static struct sh_machine_vector mv_rts7751r2d __initmv = {
|
||||||
.mv_name = "RTS7751R2D",
|
.mv_name = "RTS7751R2D",
|
||||||
.mv_setup = rts7751r2d_setup,
|
.mv_setup = rts7751r2d_setup,
|
||||||
.mv_nr_irqs = 72,
|
|
||||||
|
|
||||||
.mv_init_irq = init_rts7751r2d_IRQ,
|
.mv_init_irq = init_rts7751r2d_IRQ,
|
||||||
.mv_irq_demux = rts7751r2d_irq_demux,
|
.mv_irq_demux = rts7751r2d_irq_demux,
|
||||||
|
|
|
@ -23,149 +23,79 @@
|
||||||
#include <asm/voyagergx.h>
|
#include <asm/voyagergx.h>
|
||||||
#include <asm/rts7751r2d.h>
|
#include <asm/rts7751r2d.h>
|
||||||
|
|
||||||
static void disable_voyagergx_irq(unsigned int irq)
|
enum {
|
||||||
{
|
UNUSED = 0,
|
||||||
unsigned long val;
|
|
||||||
unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
|
|
||||||
|
|
||||||
pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
|
/* voyager specific interrupt sources */
|
||||||
val = readl((void __iomem *)VOYAGER_INT_MASK);
|
UP, G54, G53, G52, G51, G50, G49, G48,
|
||||||
val &= ~mask;
|
I2C, PW, DMA, PCI, I2S, AC, US,
|
||||||
writel(val, (void __iomem *)VOYAGER_INT_MASK);
|
U1, U0, CV, MC, S1, S0,
|
||||||
}
|
UH, TWOD, ZD, PV, CI,
|
||||||
|
|
||||||
static void enable_voyagergx_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
|
|
||||||
|
|
||||||
pr_debug("disable_voyagergx_irq(%d): mask=%lx\n", irq, mask);
|
|
||||||
val = readl((void __iomem *)VOYAGER_INT_MASK);
|
|
||||||
val |= mask;
|
|
||||||
writel(val, (void __iomem *)VOYAGER_INT_MASK);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mask_and_ack_voyagergx(unsigned int irq)
|
|
||||||
{
|
|
||||||
disable_voyagergx_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void end_voyagergx_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
|
|
||||||
enable_voyagergx_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int startup_voyagergx_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
enable_voyagergx_irq(irq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shutdown_voyagergx_irq(unsigned int irq)
|
|
||||||
{
|
|
||||||
disable_voyagergx_irq(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct hw_interrupt_type voyagergx_irq_type = {
|
|
||||||
.typename = "VOYAGERGX-IRQ",
|
|
||||||
.startup = startup_voyagergx_irq,
|
|
||||||
.shutdown = shutdown_voyagergx_irq,
|
|
||||||
.enable = enable_voyagergx_irq,
|
|
||||||
.disable = disable_voyagergx_irq,
|
|
||||||
.ack = mask_and_ack_voyagergx,
|
|
||||||
.end = end_voyagergx_irq,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
|
static struct intc_vect vectors[] = {
|
||||||
|
INTC_IRQ(UP, IRQ_SM501_UP), INTC_IRQ(G54, IRQ_SM501_G54),
|
||||||
|
INTC_IRQ(G53, IRQ_SM501_G53), INTC_IRQ(G52, IRQ_SM501_G52),
|
||||||
|
INTC_IRQ(G51, IRQ_SM501_G51), INTC_IRQ(G50, IRQ_SM501_G50),
|
||||||
|
INTC_IRQ(G49, IRQ_SM501_G49), INTC_IRQ(G48, IRQ_SM501_G48),
|
||||||
|
INTC_IRQ(I2C, IRQ_SM501_I2C), INTC_IRQ(PW, IRQ_SM501_PW),
|
||||||
|
INTC_IRQ(DMA, IRQ_SM501_DMA), INTC_IRQ(PCI, IRQ_SM501_PCI),
|
||||||
|
INTC_IRQ(I2S, IRQ_SM501_I2S), INTC_IRQ(AC, IRQ_SM501_AC),
|
||||||
|
INTC_IRQ(US, IRQ_SM501_US), INTC_IRQ(U1, IRQ_SM501_U1),
|
||||||
|
INTC_IRQ(U0, IRQ_SM501_U0), INTC_IRQ(CV, IRQ_SM501_CV),
|
||||||
|
INTC_IRQ(MC, IRQ_SM501_MC), INTC_IRQ(S1, IRQ_SM501_S1),
|
||||||
|
INTC_IRQ(S0, IRQ_SM501_S0), INTC_IRQ(UH, IRQ_SM501_UH),
|
||||||
|
INTC_IRQ(TWOD, IRQ_SM501_2D), INTC_IRQ(ZD, IRQ_SM501_ZD),
|
||||||
|
INTC_IRQ(PV, IRQ_SM501_PV), INTC_IRQ(CI, IRQ_SM501_CI),
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct intc_mask_reg mask_registers[] = {
|
||||||
|
{ VOYAGER_INT_MASK, 1, 32, /* "Interrupt Mask", MMIO_base + 0x30 */
|
||||||
|
{ UP, G54, G53, G52, G51, G50, G49, G48,
|
||||||
|
I2C, PW, 0, DMA, PCI, I2S, AC, US,
|
||||||
|
0, 0, U1, U0, CV, MC, S1, S0,
|
||||||
|
0, UH, 0, 0, TWOD, ZD, PV, CI } },
|
||||||
|
};
|
||||||
|
|
||||||
|
static DECLARE_INTC_DESC(intc_desc, "voyagergx", vectors,
|
||||||
|
NULL, NULL, mask_registers, NULL, NULL);
|
||||||
|
|
||||||
|
static unsigned int voyagergx_stat2irq[32] = {
|
||||||
|
IRQ_SM501_CI, IRQ_SM501_PV, IRQ_SM501_ZD, IRQ_SM501_2D,
|
||||||
|
0, 0, IRQ_SM501_UH, 0,
|
||||||
|
IRQ_SM501_S0, IRQ_SM501_S1, IRQ_SM501_MC, IRQ_SM501_CV,
|
||||||
|
IRQ_SM501_U0, IRQ_SM501_U1, 0, 0,
|
||||||
|
IRQ_SM501_US, IRQ_SM501_AC, IRQ_SM501_I2S, IRQ_SM501_PCI,
|
||||||
|
IRQ_SM501_DMA, 0, IRQ_SM501_PW, IRQ_SM501_I2C,
|
||||||
|
IRQ_SM501_G48, IRQ_SM501_G49, IRQ_SM501_G50, IRQ_SM501_G51,
|
||||||
|
IRQ_SM501_G52, IRQ_SM501_G53, IRQ_SM501_G54, IRQ_SM501_UP
|
||||||
|
};
|
||||||
|
|
||||||
|
static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
|
||||||
{
|
{
|
||||||
printk(KERN_INFO
|
unsigned long intv = ctrl_inl(INT_STATUS);
|
||||||
"VoyagerGX: spurious interrupt, status: 0x%x\n",
|
struct irq_desc *ext_desc;
|
||||||
(unsigned int)readl((void __iomem *)INT_STATUS));
|
unsigned int ext_irq;
|
||||||
return IRQ_HANDLED;
|
unsigned int k = 0;
|
||||||
}
|
|
||||||
|
|
||||||
static struct {
|
while (intv) {
|
||||||
int (*func)(int, void *);
|
ext_irq = voyagergx_stat2irq[k];
|
||||||
void *dev;
|
if (ext_irq && (intv & 1)) {
|
||||||
} voyagergx_demux[VOYAGER_IRQ_NUM];
|
ext_desc = irq_desc + ext_irq;
|
||||||
|
handle_level_irq(ext_irq, ext_desc);
|
||||||
void voyagergx_register_irq_demux(int irq,
|
|
||||||
int (*demux)(int irq, void *dev), void *dev)
|
|
||||||
{
|
|
||||||
voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = demux;
|
|
||||||
voyagergx_demux[irq - VOYAGER_IRQ_BASE].dev = dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void voyagergx_unregister_irq_demux(int irq)
|
|
||||||
{
|
|
||||||
voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int voyagergx_irq_demux(int irq)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (irq == IRQ_VOYAGER ) {
|
|
||||||
unsigned long i = 0, bit __attribute__ ((unused));
|
|
||||||
unsigned long val = readl((void __iomem *)INT_STATUS);
|
|
||||||
|
|
||||||
if (val & (1 << 1))
|
|
||||||
i = 1;
|
|
||||||
else if (val & (1 << 2))
|
|
||||||
i = 2;
|
|
||||||
else if (val & (1 << 6))
|
|
||||||
i = 6;
|
|
||||||
else if (val & (1 << 10))
|
|
||||||
i = 10;
|
|
||||||
else if (val & (1 << 11))
|
|
||||||
i = 11;
|
|
||||||
else if (val & (1 << 12))
|
|
||||||
i = 12;
|
|
||||||
else if (val & (1 << 17))
|
|
||||||
i = 17;
|
|
||||||
else
|
|
||||||
printk("Unexpected IRQ irq = %d status = 0x%08lx\n", irq, val);
|
|
||||||
pr_debug("voyagergx_irq_demux %ld \n", i);
|
|
||||||
if (i < VOYAGER_IRQ_NUM) {
|
|
||||||
irq = VOYAGER_IRQ_BASE + i;
|
|
||||||
if (voyagergx_demux[i].func != 0)
|
|
||||||
irq = voyagergx_demux[i].func(irq,
|
|
||||||
voyagergx_demux[i].dev);
|
|
||||||
}
|
}
|
||||||
|
intv >>= 1;
|
||||||
|
k++;
|
||||||
}
|
}
|
||||||
return irq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irqaction irq0 = {
|
|
||||||
.name = "voyagergx",
|
|
||||||
.handler = voyagergx_interrupt,
|
|
||||||
.flags = IRQF_DISABLED,
|
|
||||||
.mask = CPU_MASK_NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
void __init setup_voyagergx_irq(void)
|
void __init setup_voyagergx_irq(void)
|
||||||
{
|
{
|
||||||
int i, flag;
|
printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
|
||||||
|
|
||||||
printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
|
|
||||||
VOYAGER_BASE,
|
|
||||||
IRQ_VOYAGER,
|
IRQ_VOYAGER,
|
||||||
VOYAGER_IRQ_BASE,
|
VOYAGER_IRQ_BASE,
|
||||||
VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
|
VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);
|
||||||
|
|
||||||
for (i=0; i<VOYAGER_IRQ_NUM; i++) {
|
register_intc_controller(&intc_desc);
|
||||||
flag = 0;
|
set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
|
||||||
switch (VOYAGER_IRQ_BASE + i) {
|
|
||||||
case VOYAGER_USBH_IRQ:
|
|
||||||
case VOYAGER_8051_IRQ:
|
|
||||||
case VOYAGER_UART0_IRQ:
|
|
||||||
case VOYAGER_UART1_IRQ:
|
|
||||||
case VOYAGER_AC97_IRQ:
|
|
||||||
flag = 1;
|
|
||||||
}
|
|
||||||
if (flag == 1)
|
|
||||||
irq_desc[VOYAGER_IRQ_BASE + i].chip = &voyagergx_irq_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_irq(IRQ_VOYAGER, &irq0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,35 @@
|
||||||
#define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE)
|
#define VOYAGER_UART_BASE (0x30000 + VOYAGER_BASE)
|
||||||
#define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE)
|
#define VOYAGER_AC97_BASE (0xa0000 + VOYAGER_BASE)
|
||||||
|
|
||||||
#define VOYAGER_IRQ_NUM 32
|
#define VOYAGER_IRQ_NUM 26
|
||||||
#define VOYAGER_IRQ_BASE 50
|
#define VOYAGER_IRQ_BASE 200
|
||||||
#define VOYAGER_USBH_IRQ VOYAGER_IRQ_BASE + 6
|
|
||||||
#define VOYAGER_8051_IRQ VOYAGER_IRQ_BASE + 10
|
#define IRQ_SM501_UP (VOYAGER_IRQ_BASE + 0)
|
||||||
#define VOYAGER_UART0_IRQ VOYAGER_IRQ_BASE + 12
|
#define IRQ_SM501_G54 (VOYAGER_IRQ_BASE + 1)
|
||||||
#define VOYAGER_UART1_IRQ VOYAGER_IRQ_BASE + 13
|
#define IRQ_SM501_G53 (VOYAGER_IRQ_BASE + 2)
|
||||||
#define VOYAGER_AC97_IRQ VOYAGER_IRQ_BASE + 17
|
#define IRQ_SM501_G52 (VOYAGER_IRQ_BASE + 3)
|
||||||
|
#define IRQ_SM501_G51 (VOYAGER_IRQ_BASE + 4)
|
||||||
|
#define IRQ_SM501_G50 (VOYAGER_IRQ_BASE + 5)
|
||||||
|
#define IRQ_SM501_G49 (VOYAGER_IRQ_BASE + 6)
|
||||||
|
#define IRQ_SM501_G48 (VOYAGER_IRQ_BASE + 7)
|
||||||
|
#define IRQ_SM501_I2C (VOYAGER_IRQ_BASE + 8)
|
||||||
|
#define IRQ_SM501_PW (VOYAGER_IRQ_BASE + 9)
|
||||||
|
#define IRQ_SM501_DMA (VOYAGER_IRQ_BASE + 10)
|
||||||
|
#define IRQ_SM501_PCI (VOYAGER_IRQ_BASE + 11)
|
||||||
|
#define IRQ_SM501_I2S (VOYAGER_IRQ_BASE + 12)
|
||||||
|
#define IRQ_SM501_AC (VOYAGER_IRQ_BASE + 13)
|
||||||
|
#define IRQ_SM501_US (VOYAGER_IRQ_BASE + 14)
|
||||||
|
#define IRQ_SM501_U1 (VOYAGER_IRQ_BASE + 15)
|
||||||
|
#define IRQ_SM501_U0 (VOYAGER_IRQ_BASE + 16)
|
||||||
|
#define IRQ_SM501_CV (VOYAGER_IRQ_BASE + 17)
|
||||||
|
#define IRQ_SM501_MC (VOYAGER_IRQ_BASE + 18)
|
||||||
|
#define IRQ_SM501_S1 (VOYAGER_IRQ_BASE + 19)
|
||||||
|
#define IRQ_SM501_S0 (VOYAGER_IRQ_BASE + 20)
|
||||||
|
#define IRQ_SM501_UH (VOYAGER_IRQ_BASE + 21)
|
||||||
|
#define IRQ_SM501_2D (VOYAGER_IRQ_BASE + 22)
|
||||||
|
#define IRQ_SM501_ZD (VOYAGER_IRQ_BASE + 23)
|
||||||
|
#define IRQ_SM501_PV (VOYAGER_IRQ_BASE + 24)
|
||||||
|
#define IRQ_SM501_CI (VOYAGER_IRQ_BASE + 25)
|
||||||
|
|
||||||
/* ----- MISC controle register ------------------------------ */
|
/* ----- MISC controle register ------------------------------ */
|
||||||
#define MISC_CTRL (0x000004 + VOYAGER_BASE)
|
#define MISC_CTRL (0x000004 + VOYAGER_BASE)
|
||||||
|
@ -313,4 +335,7 @@
|
||||||
void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
|
void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
|
||||||
int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
|
int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
|
||||||
|
|
||||||
|
/* arch/sh/cchips/voyagergx/irq.c */
|
||||||
|
void setup_voyagergx_irq(void);
|
||||||
|
|
||||||
#endif /* _VOYAGER_GX_REG_H */
|
#endif /* _VOYAGER_GX_REG_H */
|
||||||
|
|
Loading…
Reference in a new issue