Commit 48180cab authored by Magnus Damm's avatar Magnus Damm Committed by Paul Mundt
Browse files

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: default avatarMagnus Damm <damm@igel.co.jp>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 51da6426
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <asm/voyagergx.h>
#include <asm/rts7751r2d.h>

#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};
#endif

extern int voyagergx_irq_demux(int irq);
extern void setup_voyagergx_irq(void);

static void enable_rts7751r2d_irq(unsigned int irq)
{
	/* 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)
{
	return voyagergx_irq_demux(irq);
	return irq;
}

static struct irq_chip rts7751r2d_irq_chip __read_mostly = {
+2 −3
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ static struct plat_serial8250_port uart_platform_data[] = {
		.membase	= (void __iomem *)VOYAGER_UART_BASE,
		.mapbase	= VOYAGER_UART_BASE,
		.iotype		= UPIO_MEM,
		.irq		= VOYAGER_UART0_IRQ,
		.irq		= IRQ_SM501_U0,
		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
		.regshift	= 2,
		.uartclk	= (9600 * 16),
@@ -125,7 +125,7 @@ static struct resource sm501_resources[] = {
		.flags	= IORESOURCE_MEM,
	},
	[2]	= {
		.start	= 32,
		.start	= IRQ_SM501_CV,
		.flags	= IORESOURCE_IRQ,
	},
};
@@ -187,7 +187,6 @@ static void __init rts7751r2d_setup(char **cmdline_p)
static struct sh_machine_vector mv_rts7751r2d __initmv = {
	.mv_name		= "RTS7751R2D",
	.mv_setup		= rts7751r2d_setup,
	.mv_nr_irqs		= 72,

	.mv_init_irq		= init_rts7751r2d_IRQ,
	.mv_irq_demux		= rts7751r2d_irq_demux,
+59 −129
Original line number Diff line number Diff line
@@ -23,149 +23,79 @@
#include <asm/voyagergx.h>
#include <asm/rts7751r2d.h>

static void disable_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 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,
enum {
	UNUSED = 0,

	/* voyager specific interrupt sources */
	UP, G54, G53, G52, G51, G50, G49, G48,
	I2C, PW, DMA, PCI, I2S, AC, US,
	U1, U0, CV, MC, S1, S0,
	UH, TWOD, ZD, PV, CI,
};

static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
{
	printk(KERN_INFO
	       "VoyagerGX: spurious interrupt, status: 0x%x\n",
			(unsigned int)readl((void __iomem *)INT_STATUS));
	return IRQ_HANDLED;
}

static struct {
	int (*func)(int, void *);
	void *dev;
} voyagergx_demux[VOYAGER_IRQ_NUM];
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),
};

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;
}
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 } },
};

void voyagergx_unregister_irq_demux(int irq)
{
	voyagergx_demux[irq - VOYAGER_IRQ_BASE].func = 0;
}
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
};

int voyagergx_irq_demux(int irq)
static void voyagergx_irq_demux(unsigned int irq, struct irq_desc *desc)
{

	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);
	unsigned long intv = ctrl_inl(INT_STATUS);
	struct irq_desc *ext_desc;
	unsigned int ext_irq;
	unsigned int k = 0;

	while (intv) {
		ext_irq = voyagergx_stat2irq[k];
		if (ext_irq && (intv & 1)) {
			ext_desc = irq_desc + ext_irq;
			handle_level_irq(ext_irq, ext_desc);
		}
		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)
{
	int i, flag;

	printk(KERN_INFO "VoyagerGX configured at 0x%x on irq %d(mapped into %d to %d)\n",
	       VOYAGER_BASE,
	printk(KERN_INFO "VoyagerGX on irq %d (mapped into %d to %d)\n",
	       IRQ_VOYAGER,
	       VOYAGER_IRQ_BASE,
	       VOYAGER_IRQ_BASE + VOYAGER_IRQ_NUM - 1);

	for (i=0; i<VOYAGER_IRQ_NUM; i++) {
		flag = 0;
		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);
	register_intc_controller(&intc_desc);
	set_irq_chained_handler(IRQ_VOYAGER, voyagergx_irq_demux);
}
+32 −7
Original line number Diff line number Diff line
@@ -27,13 +27,35 @@
#define VOYAGER_UART_BASE		(0x30000 + VOYAGER_BASE)
#define	VOYAGER_AC97_BASE		(0xa0000 + VOYAGER_BASE)

#define VOYAGER_IRQ_NUM			32
#define VOYAGER_IRQ_BASE		50
#define VOYAGER_USBH_IRQ		VOYAGER_IRQ_BASE + 6
#define VOYAGER_8051_IRQ		VOYAGER_IRQ_BASE + 10
#define VOYAGER_UART0_IRQ		VOYAGER_IRQ_BASE + 12
#define VOYAGER_UART1_IRQ		VOYAGER_IRQ_BASE + 13
#define	VOYAGER_AC97_IRQ		VOYAGER_IRQ_BASE + 17
#define VOYAGER_IRQ_NUM			26
#define VOYAGER_IRQ_BASE		200

#define IRQ_SM501_UP			(VOYAGER_IRQ_BASE + 0)
#define IRQ_SM501_G54			(VOYAGER_IRQ_BASE + 1)
#define IRQ_SM501_G53			(VOYAGER_IRQ_BASE + 2)
#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 ------------------------------ */
#define MISC_CTRL			(0x000004 + VOYAGER_BASE)
@@ -313,4 +335,7 @@
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);

/* arch/sh/cchips/voyagergx/irq.c */
void setup_voyagergx_irq(void);

#endif /* _VOYAGER_GX_REG_H */