xilinx_pic.c 3.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Interrupt controller driver for Xilinx Virtex-II Pro.
 *
 * Author: MontaVista Software, Inc.
 *         source@mvista.com
 *
 * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under
 * the terms of the GNU General Public License version 2. This program
 * is licensed "as is" without any warranty of any kind, whether express
 * or implied.
 */

#include <linux/init.h>
#include <linux/irq.h>
#include <asm/io.h>
16
#include <platforms/4xx/xparameters/xparameters.h>
L
Linus Torvalds 已提交
17
#include <asm/ibm4xx.h>
P
Paul Mackerras 已提交
18
#include <asm/machdep.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

/* No one else should require these constants, so define them locally here. */
#define ISR 0			/* Interrupt Status Register */
#define IPR 1			/* Interrupt Pending Register */
#define IER 2			/* Interrupt Enable Register */
#define IAR 3			/* Interrupt Acknowledge Register */
#define SIE 4			/* Set Interrupt Enable bits */
#define CIE 5			/* Clear Interrupt Enable bits */
#define IVR 6			/* Interrupt Vector Register */
#define MER 7			/* Master Enable Register */

#if XPAR_XINTC_USE_DCR == 0
static volatile u32 *intc;
#define intc_out_be32(addr, mask)     out_be32((addr), (mask))
#define intc_in_be32(addr)            in_be32((addr))
#else
#define intc    XPAR_INTC_0_BASEADDR
#define intc_out_be32(addr, mask)     mtdcr((addr), (mask))
#define intc_in_be32(addr)            mfdcr((addr))
#endif

static void
xilinx_intc_enable(unsigned int irq)
{
	unsigned long mask = (0x00000001 << (irq & 31));
	pr_debug("enable: %d\n", irq);
	intc_out_be32(intc + SIE, mask);
}

static void
xilinx_intc_disable(unsigned int irq)
{
	unsigned long mask = (0x00000001 << (irq & 31));
	pr_debug("disable: %d\n", irq);
	intc_out_be32(intc + CIE, mask);
}

static void
xilinx_intc_disable_and_ack(unsigned int irq)
{
	unsigned long mask = (0x00000001 << (irq & 31));
	pr_debug("disable_and_ack: %d\n", irq);
	intc_out_be32(intc + CIE, mask);
	if (!(irq_desc[irq].status & IRQ_LEVEL))
		intc_out_be32(intc + IAR, mask);	/* ack edge triggered intr */
}

static void
xilinx_intc_end(unsigned int irq)
{
	unsigned long mask = (0x00000001 << (irq & 31));

	pr_debug("end: %d\n", irq);
	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
		intc_out_be32(intc + SIE, mask);
		/* ack level sensitive intr */
		if (irq_desc[irq].status & IRQ_LEVEL)
			intc_out_be32(intc + IAR, mask);
	}
}

static struct hw_interrupt_type xilinx_intc = {
81 82 83 84 85
	.typename = "Xilinx Interrupt Controller",
	.enable = xilinx_intc_enable,
	.disable = xilinx_intc_disable,
	.ack = xilinx_intc_disable_and_ack,
	.end = xilinx_intc_end,
L
Linus Torvalds 已提交
86 87 88
};

int
A
Al Viro 已提交
89
xilinx_pic_get_irq(void)
L
Linus Torvalds 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
{
	int irq;

	/*
	 * NOTE: This function is the one that needs to be improved in
	 * order to handle multiple interrupt controllers.  It currently
	 * is hardcoded to check for interrupts only on the first INTC.
	 */

	irq = intc_in_be32(intc + IVR);
	if (irq != -1)
		irq = irq;

	pr_debug("get_irq: %d\n", irq);

	return (irq);
}

void __init
ppc4xx_pic_init(void)
{
	int i;

	/*
	 * NOTE: The assumption here is that NR_IRQS is 32 or less
	 * (NR_IRQS is 32 for PowerPC 405 cores by default).
	 */
#if (NR_IRQS > 32)
#error NR_IRQS > 32 not supported
#endif

#if XPAR_XINTC_USE_DCR == 0
	intc = ioremap(XPAR_INTC_0_BASEADDR, 32);

	printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
	       (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
#else
	printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
	       (unsigned long) XPAR_INTC_0_BASEADDR);
#endif

	/*
	 * Disable all external interrupts until they are
	 * explicity requested.
	 */
	intc_out_be32(intc + IER, 0);

	/* Acknowledge any pending interrupts just in case. */
	intc_out_be32(intc + IAR, ~(u32) 0);

	/* Turn on the Master Enable. */
	intc_out_be32(intc + MER, 0x3UL);

	ppc_md.get_irq = xilinx_pic_get_irq;

	for (i = 0; i < NR_IRQS; ++i) {
146
		irq_desc[i].chip = &xilinx_intc;
L
Linus Torvalds 已提交
147 148 149 150 151 152 153

		if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
			irq_desc[i].status &= ~IRQ_LEVEL;
		else
			irq_desc[i].status |= IRQ_LEVEL;
	}
}