Skip to content
Snippets Groups Projects
Commit 43835aac authored by Detlev Zundel's avatar Detlev Zundel
Browse files

Added interrupt handling capabilities for mpc5xxx processors.

Also added Linux like BUG() macros.
parent e8143e72
No related branches found
No related tags found
No related merge requests found
/* /*
* (C) Copyright 2006
* Detlev Zundel, DENX Software Engineering, dzu@denx.de
*
* (C) Copyright -2003 * (C) Copyright -2003
* Wolfgang Denk, DENX Software Engineering, wd@denx.de. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* *
...@@ -24,18 +27,212 @@ ...@@ -24,18 +27,212 @@
* MA 02111-1307 USA * MA 02111-1307 USA
*/ */
/* /* this section was ripped out of arch/ppc/syslib/mpc52xx_pic.c in the
* interrupts.c - just enough support for the decrementer/timer * Linux 2.6 source with the following copyright.
*
* Based on (well, mostly copied from) the code from the 2.4 kernel by
* Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
*
* Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
* Copyright (C) 2003 Montavista Software, Inc
*/ */
#include <common.h> #include <common.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/io.h>
#include <command.h> #include <command.h>
int interrupt_init_cpu (ulong *decrementer_count) struct irq_action {
interrupt_handler_t *handler;
void *arg;
ulong count;
};
static struct irq_action irq_handlers[NR_IRQS];
static struct mpc5xxx_intr *intr;
static struct mpc5xxx_sdma *sdma;
static void mpc5xxx_ic_disable(unsigned int irq)
{
u32 val;
if (irq == MPC5XXX_IRQ0) {
val = in_be32(&intr->ctrl);
val &= ~(1 << 11);
out_be32(&intr->ctrl, val);
} else if (irq < MPC5XXX_IRQ1) {
BUG();
} else if (irq <= MPC5XXX_IRQ3) {
val = in_be32(&intr->ctrl);
val &= ~(1 << (10 - (irq - MPC5XXX_IRQ1)));
out_be32(&intr->ctrl, val);
} else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
val = in_be32(&intr->main_mask);
val |= 1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE));
out_be32(&intr->main_mask, val);
} else if (irq < MPC5XXX_PERP_IRQ_BASE) {
val = in_be32(&sdma->IntMask);
val |= 1 << (irq - MPC5XXX_SDMA_IRQ_BASE);
out_be32(&sdma->IntMask, val);
} else {
val = in_be32(&intr->per_mask);
val |= 1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE));
out_be32(&intr->per_mask, val);
}
}
static void mpc5xxx_ic_enable(unsigned int irq)
{
u32 val;
if (irq == MPC5XXX_IRQ0) {
val = in_be32(&intr->ctrl);
val |= 1 << 11;
out_be32(&intr->ctrl, val);
} else if (irq < MPC5XXX_IRQ1) {
BUG();
} else if (irq <= MPC5XXX_IRQ3) {
val = in_be32(&intr->ctrl);
val |= 1 << (10 - (irq - MPC5XXX_IRQ1));
out_be32(&intr->ctrl, val);
} else if (irq < MPC5XXX_SDMA_IRQ_BASE) {
val = in_be32(&intr->main_mask);
val &= ~(1 << (16 - (irq - MPC5XXX_MAIN_IRQ_BASE)));
out_be32(&intr->main_mask, val);
} else if (irq < MPC5XXX_PERP_IRQ_BASE) {
val = in_be32(&sdma->IntMask);
val &= ~(1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
out_be32(&sdma->IntMask, val);
} else {
val = in_be32(&intr->per_mask);
val &= ~(1 << (31 - (irq - MPC5XXX_PERP_IRQ_BASE)));
out_be32(&intr->per_mask, val);
}
}
static void mpc5xxx_ic_ack(unsigned int irq)
{
u32 val;
/*
* Only some irqs are reset here, others in interrupting hardware.
*/
switch (irq) {
case MPC5XXX_IRQ0:
val = in_be32(&intr->ctrl);
val |= 0x08000000;
out_be32(&intr->ctrl, val);
break;
case MPC5XXX_CCS_IRQ:
val = in_be32(&intr->enc_status);
val |= 0x00000400;
out_be32(&intr->enc_status, val);
break;
case MPC5XXX_IRQ1:
val = in_be32(&intr->ctrl);
val |= 0x04000000;
out_be32(&intr->ctrl, val);
break;
case MPC5XXX_IRQ2:
val = in_be32(&intr->ctrl);
val |= 0x02000000;
out_be32(&intr->ctrl, val);
break;
case MPC5XXX_IRQ3:
val = in_be32(&intr->ctrl);
val |= 0x01000000;
out_be32(&intr->ctrl, val);
break;
default:
if (irq >= MPC5XXX_SDMA_IRQ_BASE
&& irq < (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)) {
out_be32(&sdma->IntPend,
1 << (irq - MPC5XXX_SDMA_IRQ_BASE));
}
break;
}
}
static void mpc5xxx_ic_disable_and_ack(unsigned int irq)
{
mpc5xxx_ic_disable(irq);
mpc5xxx_ic_ack(irq);
}
static void mpc5xxx_ic_end(unsigned int irq)
{
mpc5xxx_ic_enable(irq);
}
void mpc5xxx_init_irq(void)
{
u32 intr_ctrl;
/* Remap the necessary zones */
intr = (struct mpc5xxx_intr *)(MPC5XXX_ICTL);
sdma = (struct mpc5xxx_sdma *)(MPC5XXX_SDMA);
/* Disable all interrupt sources. */
out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
intr_ctrl = in_be32(&intr->ctrl);
intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
0x00ff0000 | /* IRQ 0-3 level sensitive low active */
0x00001000 | /* MEE master external enable */
0x00000000 | /* 0 means disable IRQ 0-3 */
0x00000001; /* CEb route critical normally */
out_be32(&intr->ctrl, intr_ctrl);
/* Zero a bunch of the priority settings. */
out_be32(&intr->per_pri1, 0);
out_be32(&intr->per_pri2, 0);
out_be32(&intr->per_pri3, 0);
out_be32(&intr->main_pri1, 0);
out_be32(&intr->main_pri2, 0);
}
int mpc5xxx_get_irq(struct pt_regs *regs)
{
u32 status;
int irq = -1;
status = in_be32(&intr->enc_status);
if (status & 0x00000400) { /* critical */
irq = (status >> 8) & 0x3;
if (irq == 2) /* high priority peripheral */
goto peripheral;
irq += MPC5XXX_CRIT_IRQ_BASE;
} else if (status & 0x00200000) { /* main */
irq = (status >> 16) & 0x1f;
if (irq == 4) /* low priority peripheral */
goto peripheral;
irq += MPC5XXX_MAIN_IRQ_BASE;
} else if (status & 0x20000000) { /* peripheral */
peripheral:
irq = (status >> 24) & 0x1f;
if (irq == 0) { /* bestcomm */
status = in_be32(&sdma->IntPend);
irq = ffs(status) + MPC5XXX_SDMA_IRQ_BASE - 1;
} else
irq += MPC5XXX_PERP_IRQ_BASE;
}
return irq;
}
/****************************************************************************/
int interrupt_init_cpu(ulong * decrementer_count)
{ {
*decrementer_count = get_tbclk() / CFG_HZ; *decrementer_count = get_tbclk() / CFG_HZ;
mpc5xxx_init_irq();
return (0); return (0);
} }
...@@ -44,14 +241,32 @@ int interrupt_init_cpu (ulong *decrementer_count) ...@@ -44,14 +241,32 @@ int interrupt_init_cpu (ulong *decrementer_count)
/* /*
* Handle external interrupts * Handle external interrupts
*/ */
void void external_interrupt(struct pt_regs *regs)
external_interrupt(struct pt_regs *regs)
{ {
puts("external_interrupt (oops!)\n"); int irq, unmask = 1;
irq = mpc5xxx_get_irq(regs);
mpc5xxx_ic_disable_and_ack(irq);
enable_interrupts();
if (irq_handlers[irq].handler != NULL)
(*irq_handlers[irq].handler) (irq_handlers[irq].arg);
else {
printf("\nBogus External Interrupt IRQ %d\n", irq);
/*
* turn off the bogus interrupt, otherwise it
* might repeat forever
*/
unmask = 0;
}
if (unmask)
mpc5xxx_ic_end(irq);
} }
void void timer_interrupt_cpu(struct pt_regs *regs)
timer_interrupt_cpu (struct pt_regs *regs)
{ {
/* nothing to do here */ /* nothing to do here */
return; return;
...@@ -63,22 +278,69 @@ timer_interrupt_cpu (struct pt_regs *regs) ...@@ -63,22 +278,69 @@ timer_interrupt_cpu (struct pt_regs *regs)
* Install and free a interrupt handler. * Install and free a interrupt handler.
*/ */
void void irq_install_handler(int irq, interrupt_handler_t * handler, void *arg)
irq_install_handler(int vec, interrupt_handler_t *handler, void *arg)
{ {
if (irq < 0 || irq >= NR_IRQS) {
printf("irq_install_handler: bad irq number %d\n", irq);
return;
}
if (irq_handlers[irq].handler != NULL)
printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n",
(ulong) handler, (ulong) irq_handlers[irq].handler);
irq_handlers[irq].handler = handler;
irq_handlers[irq].arg = arg;
mpc5xxx_ic_enable(irq);
} }
void void irq_free_handler(int irq)
irq_free_handler(int vec)
{ {
if (irq < 0 || irq >= NR_IRQS) {
printf("irq_free_handler: bad irq number %d\n", irq);
return;
}
mpc5xxx_ic_disable(irq);
irq_handlers[irq].handler = NULL;
irq_handlers[irq].arg = NULL;
} }
/****************************************************************************/ /****************************************************************************/
void #if (CONFIG_COMMANDS & CFG_CMD_IRQ)
do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[])
{ {
puts("IRQ related functions are unimplemented currently.\n"); int irq, re_enable;
u32 intr_ctrl;
char *irq_config[] = { "level sensitive, active high",
"edge sensitive, rising active edge",
"edge sensitive, falling active edge",
"level sensitive, active low"
};
re_enable = disable_interrupts();
intr_ctrl = in_be32(&intr->ctrl);
printf("Interrupt configuration:\n");
for (irq = 0; irq <= 3; irq++) {
printf("IRQ%d: %s\n", irq,
irq_config[(intr_ctrl >> (22 - 2 * irq)) & 0x3]);
}
puts("\nInterrupt-Information:\n" "Nr Routine Arg Count\n");
for (irq = 0; irq < NR_IRQS; irq++)
if (irq_handlers[irq].handler != NULL)
printf("%02d %08lx %08lx %ld\n", irq,
(ulong) irq_handlers[irq].handler,
(ulong) irq_handlers[irq].arg,
irq_handlers[irq].count);
if (re_enable)
enable_interrupts();
} }
#endif
...@@ -109,6 +109,12 @@ typedef volatile unsigned char vu_char; ...@@ -109,6 +109,12 @@ typedef volatile unsigned char vu_char;
#define debugX(level,fmt,args...) #define debugX(level,fmt,args...)
#endif /* DEBUG */ #endif /* DEBUG */
#define BUG() do { \
printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
panic("BUG!"); \
} while (0)
#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
typedef void (interrupt_handler_t)(void *); typedef void (interrupt_handler_t)(void *);
#include <asm/u-boot.h> /* boot information for Linux kernel */ #include <asm/u-boot.h> /* boot information for Linux kernel */
......
...@@ -232,6 +232,65 @@ ...@@ -232,6 +232,65 @@
#define MPC5XXX_ICTL_PER_STS (MPC5XXX_ICTL + 0x0030) #define MPC5XXX_ICTL_PER_STS (MPC5XXX_ICTL + 0x0030)
#define MPC5XXX_ICTL_BUS_STS (MPC5XXX_ICTL + 0x0038) #define MPC5XXX_ICTL_BUS_STS (MPC5XXX_ICTL + 0x0038)
#define NR_IRQS 64
/* IRQ mapping - these are our logical IRQ numbers */
#define MPC5XXX_CRIT_IRQ_NUM 4
#define MPC5XXX_MAIN_IRQ_NUM 17
#define MPC5XXX_SDMA_IRQ_NUM 17
#define MPC5XXX_PERP_IRQ_NUM 23
#define MPC5XXX_CRIT_IRQ_BASE 1
#define MPC5XXX_MAIN_IRQ_BASE (MPC5XXX_CRIT_IRQ_BASE + MPC5XXX_CRIT_IRQ_NUM)
#define MPC5XXX_SDMA_IRQ_BASE (MPC5XXX_MAIN_IRQ_BASE + MPC5XXX_MAIN_IRQ_NUM)
#define MPC5XXX_PERP_IRQ_BASE (MPC5XXX_SDMA_IRQ_BASE + MPC5XXX_SDMA_IRQ_NUM)
#define MPC5XXX_IRQ0 (MPC5XXX_CRIT_IRQ_BASE + 0)
#define MPC5XXX_SLICE_TIMER_0_IRQ (MPC5XXX_CRIT_IRQ_BASE + 1)
#define MPC5XXX_HI_INT_IRQ (MPC5XXX_CRIT_IRQ_BASE + 2)
#define MPC5XXX_CCS_IRQ (MPC5XXX_CRIT_IRQ_BASE + 3)
#define MPC5XXX_IRQ1 (MPC5XXX_MAIN_IRQ_BASE + 1)
#define MPC5XXX_IRQ2 (MPC5XXX_MAIN_IRQ_BASE + 2)
#define MPC5XXX_IRQ3 (MPC5XXX_MAIN_IRQ_BASE + 3)
#define MPC5XXX_RTC_PINT_IRQ (MPC5XXX_MAIN_IRQ_BASE + 5)
#define MPC5XXX_RTC_SINT_IRQ (MPC5XXX_MAIN_IRQ_BASE + 6)
#define MPC5XXX_RTC_GPIO_STD_IRQ (MPC5XXX_MAIN_IRQ_BASE + 7)
#define MPC5XXX_RTC_GPIO_WKUP_IRQ (MPC5XXX_MAIN_IRQ_BASE + 8)
#define MPC5XXX_TMR0_IRQ (MPC5XXX_MAIN_IRQ_BASE + 9)
#define MPC5XXX_TMR1_IRQ (MPC5XXX_MAIN_IRQ_BASE + 10)
#define MPC5XXX_TMR2_IRQ (MPC5XXX_MAIN_IRQ_BASE + 11)
#define MPC5XXX_TMR3_IRQ (MPC5XXX_MAIN_IRQ_BASE + 12)
#define MPC5XXX_TMR4_IRQ (MPC5XXX_MAIN_IRQ_BASE + 13)
#define MPC5XXX_TMR5_IRQ (MPC5XXX_MAIN_IRQ_BASE + 14)
#define MPC5XXX_TMR6_IRQ (MPC5XXX_MAIN_IRQ_BASE + 15)
#define MPC5XXX_TMR7_IRQ (MPC5XXX_MAIN_IRQ_BASE + 16)
#define MPC5XXX_SDMA_IRQ (MPC5XXX_PERP_IRQ_BASE + 0)
#define MPC5XXX_PSC1_IRQ (MPC5XXX_PERP_IRQ_BASE + 1)
#define MPC5XXX_PSC2_IRQ (MPC5XXX_PERP_IRQ_BASE + 2)
#define MPC5XXX_PSC3_IRQ (MPC5XXX_PERP_IRQ_BASE + 3)
#define MPC5XXX_PSC6_IRQ (MPC5XXX_PERP_IRQ_BASE + 4)
#define MPC5XXX_IRDA_IRQ (MPC5XXX_PERP_IRQ_BASE + 4)
#define MPC5XXX_FEC_IRQ (MPC5XXX_PERP_IRQ_BASE + 5)
#define MPC5XXX_USB_IRQ (MPC5XXX_PERP_IRQ_BASE + 6)
#define MPC5XXX_ATA_IRQ (MPC5XXX_PERP_IRQ_BASE + 7)
#define MPC5XXX_PCI_CNTRL_IRQ (MPC5XXX_PERP_IRQ_BASE + 8)
#define MPC5XXX_PCI_SCIRX_IRQ (MPC5XXX_PERP_IRQ_BASE + 9)
#define MPC5XXX_PCI_SCITX_IRQ (MPC5XXX_PERP_IRQ_BASE + 10)
#define MPC5XXX_PSC4_IRQ (MPC5XXX_PERP_IRQ_BASE + 11)
#define MPC5XXX_PSC5_IRQ (MPC5XXX_PERP_IRQ_BASE + 12)
#define MPC5XXX_SPI_MODF_IRQ (MPC5XXX_PERP_IRQ_BASE + 13)
#define MPC5XXX_SPI_SPIF_IRQ (MPC5XXX_PERP_IRQ_BASE + 14)
#define MPC5XXX_I2C1_IRQ (MPC5XXX_PERP_IRQ_BASE + 15)
#define MPC5XXX_I2C2_IRQ (MPC5XXX_PERP_IRQ_BASE + 16)
#define MPC5XXX_MSCAN1_IRQ (MPC5XXX_PERP_IRQ_BASE + 17)
#define MPC5XXX_MSCAN2_IRQ (MPC5XXX_PERP_IRQ_BASE + 18)
#define MPC5XXX_IR_RX_IRQ (MPC5XXX_PERP_IRQ_BASE + 19)
#define MPC5XXX_IR_TX_IRQ (MPC5XXX_PERP_IRQ_BASE + 20)
#define MPC5XXX_XLB_ARB_IRQ (MPC5XXX_PERP_IRQ_BASE + 21)
#define MPC5XXX_BDLC_IRQ (MPC5XXX_PERP_IRQ_BASE + 22)
/* General Purpose Timers registers */ /* General Purpose Timers registers */
#define MPC5XXX_GPT0_ENABLE (MPC5XXX_GPT + 0x0) #define MPC5XXX_GPT0_ENABLE (MPC5XXX_GPT + 0x0)
#define MPC5XXX_GPT0_COUNTER (MPC5XXX_GPT + 0x4) #define MPC5XXX_GPT0_COUNTER (MPC5XXX_GPT + 0x4)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment