mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
m68knommu: create a speciailized ColdFire 5272 interrupt controller
The ColdFire 5272 CPU has a very different interrupt controller than any of the other ColdFire parts. It needs its own controller code to correctly setup and ack interrupts. Signed-off-by: Greg Ungerer <gerg@uclinux.org>
This commit is contained in:
parent
da3601a5fa
commit
9075216d2c
4 changed files with 174 additions and 5 deletions
|
@ -12,7 +12,6 @@
|
|||
#define m5272sim_h
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* Define the 5272 SIM register set addresses.
|
||||
*/
|
||||
|
@ -76,8 +75,40 @@
|
|||
/*
|
||||
* Define system peripheral IRQ usage.
|
||||
*/
|
||||
#define MCF_IRQ_TIMER 69 /* Timer0, Level 6 */
|
||||
#define MCF_IRQ_PROFILER 70 /* Timer1, Level 7 */
|
||||
#define MCFINT_VECBASE 64 /* Base of interrupts */
|
||||
#define MCF_IRQ_SPURIOUS 64 /* User Spurious */
|
||||
#define MCF_IRQ_EINT1 65 /* External Interrupt 1 */
|
||||
#define MCF_IRQ_EINT2 66 /* External Interrupt 2 */
|
||||
#define MCF_IRQ_EINT3 67 /* External Interrupt 3 */
|
||||
#define MCF_IRQ_EINT4 68 /* External Interrupt 4 */
|
||||
#define MCF_IRQ_TIMER1 69 /* Timer 1 */
|
||||
#define MCF_IRQ_TIMER2 70 /* Timer 2 */
|
||||
#define MCF_IRQ_TIMER3 71 /* Timer 3 */
|
||||
#define MCF_IRQ_TIMER4 72 /* Timer 4 */
|
||||
#define MCF_IRQ_UART1 73 /* UART 1 */
|
||||
#define MCF_IRQ_UART2 74 /* UART 2 */
|
||||
#define MCF_IRQ_PLIP 75 /* PLIC 2Khz Periodic */
|
||||
#define MCF_IRQ_PLIA 76 /* PLIC Asynchronous */
|
||||
#define MCF_IRQ_USB0 77 /* USB Endpoint 0 */
|
||||
#define MCF_IRQ_USB1 78 /* USB Endpoint 1 */
|
||||
#define MCF_IRQ_USB2 79 /* USB Endpoint 2 */
|
||||
#define MCF_IRQ_USB3 80 /* USB Endpoint 3 */
|
||||
#define MCF_IRQ_USB4 81 /* USB Endpoint 4 */
|
||||
#define MCF_IRQ_USB5 82 /* USB Endpoint 5 */
|
||||
#define MCF_IRQ_USB6 83 /* USB Endpoint 6 */
|
||||
#define MCF_IRQ_USB7 84 /* USB Endpoint 7 */
|
||||
#define MCF_IRQ_DMA 85 /* DMA Controller */
|
||||
#define MCF_IRQ_ERX 86 /* Ethernet Receiver */
|
||||
#define MCF_IRQ_ETX 87 /* Ethernet Transmitter */
|
||||
#define MCF_IRQ_ENTC 88 /* Ethernet Non-Time Critical */
|
||||
#define MCF_IRQ_QSPI 89 /* Queued Serial Interface */
|
||||
#define MCF_IRQ_EINT5 90 /* External Interrupt 5 */
|
||||
#define MCF_IRQ_EINT6 91 /* External Interrupt 6 */
|
||||
#define MCF_IRQ_SWTO 92 /* Software Watchdog */
|
||||
#define MCFINT_VECMAX 95 /* Maxmum interrupt */
|
||||
|
||||
#define MCF_IRQ_TIMER MCF_IRQ_TIMER1
|
||||
#define MCF_IRQ_PROFILER MCF_IRQ_TIMER2
|
||||
|
||||
/*
|
||||
* Generic GPIO support
|
||||
|
|
|
@ -14,5 +14,5 @@
|
|||
|
||||
asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1
|
||||
|
||||
obj-y := config.o gpio.o
|
||||
obj-y := config.o gpio.o intc.o
|
||||
|
||||
|
|
138
arch/m68knommu/platform/5272/intc.c
Normal file
138
arch/m68knommu/platform/5272/intc.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* intc.c -- interrupt controller or ColdFire 5272 SoC
|
||||
*
|
||||
* (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com>
|
||||
*
|
||||
* 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
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/coldfire.h>
|
||||
#include <asm/mcfsim.h>
|
||||
#include <asm/traps.h>
|
||||
|
||||
/*
|
||||
* The 5272 ColdFire interrupt controller is nothing like any other
|
||||
* ColdFire interrupt controller - it truly is completely different.
|
||||
* Given its age it is unlikely to be used on any other ColdFire CPU.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The masking and priproty setting of interrupts on the 5272 is done
|
||||
* via a set of 4 "Interrupt Controller Registers" (ICR). There is a
|
||||
* loose mapping of vector number to register and internal bits, but
|
||||
* a table is the easiest and quickest way to map them.
|
||||
*/
|
||||
struct irqmap {
|
||||
unsigned char icr;
|
||||
unsigned char index;
|
||||
unsigned char ack;
|
||||
};
|
||||
|
||||
static struct irqmap intc_irqmap[MCFINT_VECMAX - MCFINT_VECBASE] = {
|
||||
/*MCF_IRQ_SPURIOUS*/ { .icr = 0, .index = 0, .ack = 0, },
|
||||
/*MCF_IRQ_EINT1*/ { .icr = MCFSIM_ICR1, .index = 28, .ack = 1, },
|
||||
/*MCF_IRQ_EINT2*/ { .icr = MCFSIM_ICR1, .index = 24, .ack = 1, },
|
||||
/*MCF_IRQ_EINT3*/ { .icr = MCFSIM_ICR1, .index = 20, .ack = 1, },
|
||||
/*MCF_IRQ_EINT4*/ { .icr = MCFSIM_ICR1, .index = 16, .ack = 1, },
|
||||
/*MCF_IRQ_TIMER1*/ { .icr = MCFSIM_ICR1, .index = 12, .ack = 0, },
|
||||
/*MCF_IRQ_TIMER2*/ { .icr = MCFSIM_ICR1, .index = 8, .ack = 0, },
|
||||
/*MCF_IRQ_TIMER3*/ { .icr = MCFSIM_ICR1, .index = 4, .ack = 0, },
|
||||
/*MCF_IRQ_TIMER4*/ { .icr = MCFSIM_ICR1, .index = 0, .ack = 0, },
|
||||
/*MCF_IRQ_UART1*/ { .icr = MCFSIM_ICR2, .index = 28, .ack = 0, },
|
||||
/*MCF_IRQ_UART2*/ { .icr = MCFSIM_ICR2, .index = 24, .ack = 0, },
|
||||
/*MCF_IRQ_PLIP*/ { .icr = MCFSIM_ICR2, .index = 20, .ack = 0, },
|
||||
/*MCF_IRQ_PLIA*/ { .icr = MCFSIM_ICR2, .index = 16, .ack = 0, },
|
||||
/*MCF_IRQ_USB0*/ { .icr = MCFSIM_ICR2, .index = 12, .ack = 0, },
|
||||
/*MCF_IRQ_USB1*/ { .icr = MCFSIM_ICR2, .index = 8, .ack = 0, },
|
||||
/*MCF_IRQ_USB2*/ { .icr = MCFSIM_ICR2, .index = 4, .ack = 0, },
|
||||
/*MCF_IRQ_USB3*/ { .icr = MCFSIM_ICR2, .index = 0, .ack = 0, },
|
||||
/*MCF_IRQ_USB4*/ { .icr = MCFSIM_ICR3, .index = 28, .ack = 0, },
|
||||
/*MCF_IRQ_USB5*/ { .icr = MCFSIM_ICR3, .index = 24, .ack = 0, },
|
||||
/*MCF_IRQ_USB6*/ { .icr = MCFSIM_ICR3, .index = 20, .ack = 0, },
|
||||
/*MCF_IRQ_USB7*/ { .icr = MCFSIM_ICR3, .index = 16, .ack = 0, },
|
||||
/*MCF_IRQ_DMA*/ { .icr = MCFSIM_ICR3, .index = 12, .ack = 0, },
|
||||
/*MCF_IRQ_ERX*/ { .icr = MCFSIM_ICR3, .index = 8, .ack = 0, },
|
||||
/*MCF_IRQ_ETX*/ { .icr = MCFSIM_ICR3, .index = 4, .ack = 0, },
|
||||
/*MCF_IRQ_ENTC*/ { .icr = MCFSIM_ICR3, .index = 0, .ack = 0, },
|
||||
/*MCF_IRQ_QSPI*/ { .icr = MCFSIM_ICR4, .index = 28, .ack = 0, },
|
||||
/*MCF_IRQ_EINT5*/ { .icr = MCFSIM_ICR4, .index = 24, .ack = 1, },
|
||||
/*MCF_IRQ_EINT6*/ { .icr = MCFSIM_ICR4, .index = 20, .ack = 1, },
|
||||
/*MCF_IRQ_SWTO*/ { .icr = MCFSIM_ICR4, .index = 16, .ack = 0, },
|
||||
};
|
||||
|
||||
static void intc_irq_mask(unsigned int irq)
|
||||
{
|
||||
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
|
||||
u32 v;
|
||||
irq -= MCFINT_VECBASE;
|
||||
v = 0x8 << intc_irqmap[irq].index;
|
||||
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
|
||||
}
|
||||
}
|
||||
|
||||
static void intc_irq_unmask(unsigned int irq)
|
||||
{
|
||||
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
|
||||
u32 v;
|
||||
irq -= MCFINT_VECBASE;
|
||||
v = 0xd << intc_irqmap[irq].index;
|
||||
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
|
||||
}
|
||||
}
|
||||
|
||||
static void intc_irq_ack(unsigned int irq)
|
||||
{
|
||||
/* Only external interrupts are acked */
|
||||
if ((irq >= MCFINT_VECBASE) && (irq <= MCFINT_VECMAX)) {
|
||||
irq -= MCFINT_VECBASE;
|
||||
if (intc_irqmap[irq].ack) {
|
||||
u32 v;
|
||||
v = 0xd << intc_irqmap[irq].index;
|
||||
writel(v, MCF_MBAR + intc_irqmap[irq].icr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int intc_irq_set_type(unsigned int irq, unsigned int type)
|
||||
{
|
||||
/* We can set the edge type here for external interrupts */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip intc_irq_chip = {
|
||||
.name = "CF-INTC",
|
||||
.mask = intc_irq_mask,
|
||||
.unmask = intc_irq_unmask,
|
||||
.ack = intc_irq_ack,
|
||||
.set_type = intc_irq_set_type,
|
||||
};
|
||||
|
||||
void __init init_IRQ(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
init_vectors();
|
||||
|
||||
/* Mask all interrupt sources */
|
||||
writel(0x88888888, MCF_MBAR + MCFSIM_ICR1);
|
||||
writel(0x88888888, MCF_MBAR + MCFSIM_ICR2);
|
||||
writel(0x88888888, MCF_MBAR + MCFSIM_ICR3);
|
||||
writel(0x88888888, MCF_MBAR + MCFSIM_ICR4);
|
||||
|
||||
for (irq = 0; (irq < NR_IRQS); irq++) {
|
||||
irq_desc[irq].status = IRQ_DISABLED;
|
||||
irq_desc[irq].action = NULL;
|
||||
irq_desc[irq].depth = 1;
|
||||
irq_desc[irq].chip = &intc_irq_chip;
|
||||
intc_irq_set_type(irq, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ obj-$(CONFIG_M520x) += pit.o intc-simr.o
|
|||
obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o
|
||||
obj-$(CONFIG_M5249) += timers.o intc.o
|
||||
obj-$(CONFIG_M527x) += pit.o intc-2.o
|
||||
obj-$(CONFIG_M5272) += timers.o intc.o
|
||||
obj-$(CONFIG_M5272) += timers.o
|
||||
obj-$(CONFIG_M528x) += pit.o intc-2.o
|
||||
obj-$(CONFIG_M5307) += timers.o intc.o
|
||||
obj-$(CONFIG_M532x) += timers.o intc-simr.o
|
||||
|
|
Loading…
Reference in a new issue