fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_pic.c
index 4ac2de2..ee0da4b 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * arch/ppc/syslib/ppc4xx_pic.c
- *
  * Interrupt controller driver for PowerPC 4xx-based processors.
  *
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2004 Zultys Technologies
+ * Copyright (c) 2004, 2005 Zultys Technologies
  *
  * Based on original code by
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
@@ -15,7 +13,6 @@
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
 */
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/ppc4xx_pic.h>
+#include <asm/machdep.h>
 
 /* 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 chareirqs = 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_settingsp = 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;
        }