X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fppc%2Fsyslib%2Fppc4xx_pic.c;h=ee0da4b4b993c41f81750facfc7a091b6a056b3d;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=4ac2de28c28c994f6c2245fecfd7280f006497ee;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c index 4ac2de28c..ee0da4b4b 100644 --- a/arch/ppc/syslib/ppc4xx_pic.c +++ b/arch/ppc/syslib/ppc4xx_pic.c @@ -1,10 +1,8 @@ /* - * arch/ppc/syslib/ppc4xx_pic.c - * * Interrupt controller driver for PowerPC 4xx-based processors. * * Eugene Surovegin or - * Copyright (c) 2004 Zultys Technologies + * Copyright (c) 2004, 2005 Zultys Technologies * * Based on original code by * Copyright (c) 1999 Grant Erickson @@ -15,7 +13,6 @@ * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. */ -#include #include #include #include @@ -25,22 +22,28 @@ #include #include #include +#include /* See comment in include/arch-ppc/ppc4xx_pic.h * for more info about these two variables */ -extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] __attribute__((weak)); -extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__((weak)); +extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS] + __attribute__ ((weak)); +extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak)); #define IRQ_MASK_UIC0(irq) (1 << (31 - (irq))) #define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f))) #define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq) #define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq) +#define IRQ_MASK_UIC3(irq) IRQ_MASK_UICx(irq) #define UIC_HANDLERS(n) \ static void ppc4xx_uic##n##_enable(unsigned int irq) \ { \ - ppc_cached_irq_mask[n] |= IRQ_MASK_UIC##n(irq); \ + u32 mask = IRQ_MASK_UIC##n(irq); \ + if (irq_desc[irq].status & IRQ_LEVEL) \ + mtdcr(DCRN_UIC_SR(UIC##n), mask); \ + ppc_cached_irq_mask[n] |= mask; \ mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \ } \ \ @@ -48,6 +51,7 @@ static void ppc4xx_uic##n##_disable(unsigned int irq) \ { \ ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq); \ mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \ + ACK_UIC##n##_PARENT \ } \ \ static void ppc4xx_uic##n##_ack(unsigned int irq) \ @@ -63,11 +67,11 @@ static void ppc4xx_uic##n##_end(unsigned int irq) \ { \ unsigned int status = irq_desc[irq].status; \ u32 mask = IRQ_MASK_UIC##n(irq); \ - if (status & IRQ_LEVEL){ \ + if (status & IRQ_LEVEL) { \ mtdcr(DCRN_UIC_SR(UIC##n), mask); \ ACK_UIC##n##_PARENT \ } \ - if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))){ \ + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \ ppc_cached_irq_mask[n] |= mask; \ mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \ } \ @@ -82,13 +86,46 @@ static void ppc4xx_uic##n##_end(unsigned int irq) \ .end = ppc4xx_uic##n##_end, \ } \ -#if NR_UICS == 3 +#if NR_UICS == 4 +#define ACK_UIC0_PARENT +#define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC); +#define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC2NC); +#define ACK_UIC3_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC3NC); +UIC_HANDLERS(0); +UIC_HANDLERS(1); +UIC_HANDLERS(2); +UIC_HANDLERS(3); + +static int ppc4xx_pic_get_irq(void) +{ + u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); + if (uic0 & UIC0_UIC1NC) + return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1))); + else if (uic0 & UIC0_UIC2NC) + return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2))); + else if (uic0 & UIC0_UIC3NC) + return 128 - ffs(mfdcr(DCRN_UIC_MSR(UIC3))); + else + return uic0 ? 32 - ffs(uic0) : -1; +} + +static void __init ppc4xx_pic_impl_init(void) +{ + /* Enable cascade interrupts in UIC0 */ + ppc_cached_irq_mask[0] |= UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC; + mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC | UIC0_UIC2NC | UIC0_UIC3NC); + mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]); +} + +#elif NR_UICS == 3 #define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC); #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC); #define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC); -UIC_HANDLERS(0); UIC_HANDLERS(1); UIC_HANDLERS(2); +UIC_HANDLERS(0); +UIC_HANDLERS(1); +UIC_HANDLERS(2); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uicb = mfdcr(DCRN_UIC_MSR(UICB)); if (uicb & UICB_UIC0NC) @@ -103,6 +140,10 @@ static int ppc4xx_pic_get_irq(struct pt_regs *regs) static void __init ppc4xx_pic_impl_init(void) { +#if defined(CONFIG_440GX) + /* Disable 440GP compatibility mode if it was enabled in firmware */ + SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~DCRN_SDR_MFR_PCM); +#endif /* Configure Base UIC */ mtdcr(DCRN_UIC_CR(UICB), 0); mtdcr(DCRN_UIC_TR(UICB), 0); @@ -114,9 +155,10 @@ static void __init ppc4xx_pic_impl_init(void) #elif NR_UICS == 2 #define ACK_UIC0_PARENT #define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC); -UIC_HANDLERS(0); UIC_HANDLERS(1); +UIC_HANDLERS(0); +UIC_HANDLERS(1); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); if (uic0 & UIC0_UIC1NC) @@ -137,24 +179,29 @@ static void __init ppc4xx_pic_impl_init(void) #define ACK_UIC0_PARENT UIC_HANDLERS(0); -static int ppc4xx_pic_get_irq(struct pt_regs *regs) +static int ppc4xx_pic_get_irq(void) { u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0)); return uic0 ? 32 - ffs(uic0) : -1; } -static inline void ppc4xx_pic_impl_init(void){} +static inline void ppc4xx_pic_impl_init(void) +{ +} #endif static struct ppc4xx_uic_impl { struct hw_interrupt_type decl; - int base; /* Base DCR number */ + int base; /* Base DCR number */ } __uic[] = { - { .decl = DECLARE_UIC(0), .base = UIC0 }, + { .decl = DECLARE_UIC(0), .base = UIC0 }, #if NR_UICS > 1 - { .decl = DECLARE_UIC(1), .base = UIC1 }, + { .decl = DECLARE_UIC(1), .base = UIC1 }, #if NR_UICS > 2 - { .decl = DECLARE_UIC(2), .base = UIC2 }, + { .decl = DECLARE_UIC(2), .base = UIC2 }, +#if NR_UICS > 3 + { .decl = DECLARE_UIC(3), .base = UIC3 }, +#endif #endif #endif }; @@ -168,9 +215,9 @@ static inline int is_level_sensitive(int irq) void __init ppc4xx_pic_init(void) { int i; - unsigned char* eirqs = ppc4xx_uic_ext_irq_cfg; + unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg; - for (i = 0; i < NR_UICS; ++i){ + for (i = 0; i < NR_UICS; ++i) { int base = __uic[i].base; /* Disable everything by default */ @@ -181,23 +228,23 @@ void __init ppc4xx_pic_init(void) mtdcr(DCRN_UIC_CR(base), 0); /* Configure polarity and triggering */ - if (ppc4xx_core_uic_cfg){ - struct ppc4xx_uic_settings* p = ppc4xx_core_uic_cfg + i; + if (ppc4xx_core_uic_cfg) { + struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i; u32 mask = p->ext_irq_mask; u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask; u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask; /* "Fixed" interrupts (on-chip devices) */ - pr |= p->polarity & ~mask; + pr |= p->polarity & ~mask; tr |= p->triggering & ~mask; /* Merge external IRQs settings if board port * provided them */ - if (eirqs && mask){ + if (eirqs && mask) { pr &= ~mask; tr &= ~mask; - while (mask){ + while (mask) { /* Extract current external IRQ mask */ u32 eirq_mask = 1 << __ilog2(mask); @@ -227,8 +274,8 @@ void __init ppc4xx_pic_init(void) ppc4xx_pic_impl_init(); /* Attach low-level handlers */ - for (i = 0; i < (NR_UICS << 5); ++i){ - irq_desc[i].handler = &__uic[i >> 5].decl; + for (i = 0; i < (NR_UICS << 5); ++i) { + irq_desc[i].chip = &__uic[i >> 5].decl; if (is_level_sensitive(i)) irq_desc[i].status |= IRQ_LEVEL; }