vserver 1.9.5.x5
[linux-2.6.git] / arch / ppc / syslib / ppc4xx_pic.c
index 2dc63a5..4ac2de2 100644 (file)
@@ -1,31 +1,21 @@
 /*
+ * arch/ppc/syslib/ppc4xx_pic.c
  *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: ppc4xx_pic.c
- *
- *    Description:
- *      Interrupt controller driver for PowerPC 4xx-based processors.
- */
-
-/*
- * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
- * 32 possible interrupts, a majority of which are not implemented on
- * all cores. There are six configurable, external interrupt pins and
- * there are eight internal interrupts for the on-chip serial port
- * (SPU), DMA controller, and JTAG controller.
+ * Interrupt controller driver for PowerPC 4xx-based processors.
  *
- * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has
- * 32 possible interrupts as well.  Depending on the core and SoC
- * implementation, a portion of the interrrupts are used for on-chip
- * peripherals and a portion of the interrupts are available to be
- * configured for external devices generating interrupts.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2004 Zultys Technologies
  *
- * The PowerNP and 440GP (and most likely future implementations) have
- * cascaded UICs.
+ * Based on original code by
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *    Armin Custer <akuster@mvista.com>
  *
- */
-
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * 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/irq.h>
 #include <asm/ppc4xx_pic.h>
 
-/* Global Variables */
-struct hw_interrupt_type *ppc4xx_pic;
-/*
- * We define 4xxIRQ_InitSenses table thusly:
- * bit 0x1: sense, 1 for edge and 0 for level.
- * bit 0x2: polarity, 0 for negative, 1 for positive.
- */
-unsigned int ibm4xxPIC_NumInitSenses __initdata = 0;
-unsigned char *ibm4xxPIC_InitSenses __initdata = NULL;
-
-/* Six of one, half dozen of the other....#ifdefs, separate files,
- * other tricks.....
- *
- * There are basically two types of interrupt controllers, the 403 AIC
- * and the "others" with UIC.  I just kept them both here separated
- * with #ifdefs, but it seems to change depending upon how supporting
- * files (like ppc4xx.h) change.               -- Dan.
+/* See comment in include/arch-ppc/ppc4xx_pic.h
+ * for more info about these two variables
  */
-
-#ifdef CONFIG_403
-
-/* Function Prototypes */
-
-static void ppc403_aic_enable(unsigned int irq);
-static void ppc403_aic_disable(unsigned int irq);
-static void ppc403_aic_disable_and_ack(unsigned int irq);
-
-static struct hw_interrupt_type ppc403_aic = {
-       "403GC AIC",
-       NULL,
-       NULL,
-       ppc403_aic_enable,
-       ppc403_aic_disable,
-       ppc403_aic_disable_and_ack,
-       0
-};
-
-int
-ppc403_pic_get_irq(struct pt_regs *regs)
-{
-       int irq;
-       unsigned long bits;
-
-       /*
-        * Only report the status of those interrupts that are actually
-        * enabled.
-        */
-
-       bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
-
-       /*
-        * Walk through the interrupts from highest priority to lowest, and
-        * report the first pending interrupt found.
-        * We want PPC, not C bit numbering, so just subtract the ffs()
-        * result from 32.
-        */
-       irq = 32 - ffs(bits);
-
-       if (irq == NR_AIC_IRQS)
-               irq = -1;
-
-       return (irq);
+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 UIC_HANDLERS(n)                                                        \
+static void ppc4xx_uic##n##_enable(unsigned int irq)                   \
+{                                                                      \
+       ppc_cached_irq_mask[n] |= IRQ_MASK_UIC##n(irq);                 \
+       mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);             \
+}                                                                      \
+                                                                       \
+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]);             \
+}                                                                      \
+                                                                       \
+static void ppc4xx_uic##n##_ack(unsigned int irq)                      \
+{                                                                      \
+       u32 mask = IRQ_MASK_UIC##n(irq);                                \
+       ppc_cached_irq_mask[n] &= ~mask;                                \
+       mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);             \
+       mtdcr(DCRN_UIC_SR(UIC##n), mask);                               \
+       ACK_UIC##n##_PARENT                                             \
+}                                                                      \
+                                                                       \
+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){                                        \
+               mtdcr(DCRN_UIC_SR(UIC##n), mask);                       \
+               ACK_UIC##n##_PARENT                                     \
+       }                                                               \
+       if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))){               \
+               ppc_cached_irq_mask[n] |= mask;                         \
+               mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]);     \
+       }                                                               \
 }
 
-static void
-ppc403_aic_enable(unsigned int irq)
+#define DECLARE_UIC(n)                                                 \
+{                                                                      \
+       .typename       = "UIC"#n,                                      \
+       .enable         = ppc4xx_uic##n##_enable,                       \
+       .disable        = ppc4xx_uic##n##_disable,                      \
+       .ack            = ppc4xx_uic##n##_ack,                          \
+       .end            = ppc4xx_uic##n##_end,                          \
+}                                                                      \
+
+#if 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);
+
+static int ppc4xx_pic_get_irq(struct pt_regs *regs)
 {
-       int bit, word;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
-
-       ppc_cached_irq_mask[word] |= (1 << (31 - bit));
-       mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+       u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
+       if (uicb & UICB_UIC0NC)
+               return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
+       else if (uicb & UICB_UIC1NC)
+               return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
+       else if (uicb & UICB_UIC2NC)
+               return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
+       else
+               return -1;
 }
 
-static void
-ppc403_aic_disable(unsigned int irq)
+static void __init ppc4xx_pic_impl_init(void)
 {
-       int bit, word;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
-
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-       mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
-}
-
-static void
-ppc403_aic_disable_and_ack(unsigned int irq)
-{
-       int bit, word;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
-
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-       mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
-       mtdcr(DCRN_EXISR, (1 << (31 - bit)));
+       /* Configure Base UIC */
+       mtdcr(DCRN_UIC_CR(UICB), 0);
+       mtdcr(DCRN_UIC_TR(UICB), 0);
+       mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
+       mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
+       mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
 }
 
-#else
+#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);
 
-#ifndef UIC1
-#define UIC1 UIC0
-#endif
-#ifndef UIC2
-#define UIC2 UIC1
-#endif
-
-static void
-ppc4xx_uic_enable(unsigned int irq)
+static int ppc4xx_pic_get_irq(struct pt_regs *regs)
 {
-       int bit, word;
-       irq_desc_t *desc = irq_desc + irq;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
-
-#ifdef UIC_DEBUG
-       printk("ppc4xx_uic_enable - irq %d word %d bit 0x%x\n", irq, word, bit);
-#endif
-       ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-       switch (word) {
-       case 0:
-               mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-               if ((mfdcr(DCRN_UIC_TR(UIC0)) & (1 << (31 - bit))) == 0)
-                       desc->status |= IRQ_LEVEL;
-               else
-                       desc->status = desc->status & ~IRQ_LEVEL;
-               break;
-       case 1:
-               mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-               if ((mfdcr(DCRN_UIC_TR(UIC1)) & (1 << (31 - bit))) == 0)
-                       desc->status |= IRQ_LEVEL;
-               else
-                       desc->status = desc->status & ~IRQ_LEVEL;
-               break;
-       case 2:
-               mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]);
-               if ((mfdcr(DCRN_UIC_TR(UIC2)) & (1 << (31 - bit))) == 0)
-                       desc->status |= IRQ_LEVEL;
-               else
-                       desc->status = desc->status & ~IRQ_LEVEL;
-               break;
-       }
-
+       u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
+       if (uic0 & UIC0_UIC1NC)
+               return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
+       else
+               return uic0 ? 32 - ffs(uic0) : -1;
 }
 
-static void
-ppc4xx_uic_disable(unsigned int irq)
+static void __init ppc4xx_pic_impl_init(void)
 {
-       int bit, word;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
-#ifdef UIC_DEBUG
-       printk("ppc4xx_uic_disable - irq %d word %d bit 0x%x\n", irq, word,
-              bit);
-#endif
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-       switch (word) {
-       case 0:
-               mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-               break;
-       case 1:
-               mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-               break;
-       case 2:
-               mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]);
-               break;
-       }
+       /* Enable cascade interrupt in UIC0 */
+       ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
+       mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
+       mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
 }
 
-static void
-ppc4xx_uic_disable_and_ack(unsigned int irq)
-{
-       int bit, word;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
+#elif NR_UICS == 1
+#define ACK_UIC0_PARENT
+UIC_HANDLERS(0);
 
-#ifdef UIC_DEBUG
-       printk("ppc4xx_uic_disable_and_ack - irq %d word %d bit 0x%x\n", irq,
-              word, bit);
-#endif
-       ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-       switch (word) {
-       case 0:
-               mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-               mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
-#if (NR_UICS > 2)
-               mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
-#endif
-               break;
-       case 1:
-               mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-               mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
-#if (NR_UICS == 2)
-               mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - UIC0_UIC1NC)));
-#endif
-#if (NR_UICS > 2)
-               mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
-#endif
-               break;
-       case 2:
-               mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]);
-               mtdcr(DCRN_UIC_SR(UIC2), (1 << (31 - bit)));
-#if (NR_UICS > 2)
-               mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
-#endif
-               break;
-       }
-
-}
-
-static void
-ppc4xx_uic_end(unsigned int irq)
+static int ppc4xx_pic_get_irq(struct pt_regs *regs)
 {
-       int bit, word;
-       unsigned int tr_bits = 0;
-
-       bit = irq & 0x1f;
-       word = irq >> 5;
+       u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
+       return uic0 ? 32 - ffs(uic0) : -1;
+}
 
-#ifdef UIC_DEBUG
-       printk("ppc4xx_uic_end - irq %d word %d bit 0x%x\n", irq, word, bit);
+static inline void ppc4xx_pic_impl_init(void){}
 #endif
 
-       switch (word) {
-       case 0:
-               tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
-               break;
-       case 1:
-               tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
-               break;
-       case 2:
-               tr_bits = mfdcr(DCRN_UIC_TR(UIC2));
-               break;
-       }
-
-       if ((tr_bits & (1 << (31 - bit))) == 0) {
-               /* level trigger */
-               switch (word) {
-               case 0:
-                       mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
-#if (NR_UICS > 2)
-                       mtdcr(DCRN_UIC_SR(UICB),  UICB_UIC0NC);
-#endif
-                       break;
-               case 1:
-                       mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
-#if (NR_UICS == 2)
-                       mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - UIC0_UIC1NC)));
-#endif
-#if (NR_UICS > 2)
-                       mtdcr(DCRN_UIC_SR(UICB),  UICB_UIC1NC);
-#endif
-                       break;
-               case 2:
-                       mtdcr(DCRN_UIC_SR(UIC2), 1 << (31 - bit));
-#if (NR_UICS > 2)
-                       mtdcr(DCRN_UIC_SR(UICB),  UICB_UIC2NC);
+static struct ppc4xx_uic_impl {
+       struct hw_interrupt_type decl;
+       int                      base;          /* Base DCR number */
+} __uic[] = {
+    { .decl = DECLARE_UIC(0), .base = UIC0 },
+#if NR_UICS > 1
+    { .decl = DECLARE_UIC(1), .base = UIC1 },
+#if NR_UICS > 2
+    { .decl = DECLARE_UIC(2), .base = UIC2 },
 #endif
-                       break;
-               }
-       }
-
-       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-               ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-               switch (word) {
-               case 0:
-                       mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-                       break;
-               case 1:
-                       mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-                       break;
-               case 2:
-                       mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[word]);
-                       break;
-               }
-       }
-}
-
-static struct hw_interrupt_type ppc4xx_uic = {
-#if (NR_UICS == 1)
-       "IBM UIC",
-#else
-       "IBM UIC Cascade",
 #endif
-       NULL,
-       NULL,
-       ppc4xx_uic_enable,
-       ppc4xx_uic_disable,
-       ppc4xx_uic_disable_and_ack,
-       ppc4xx_uic_end,
-       0
 };
 
-int
-ppc4xx_pic_get_irq(struct pt_regs *regs)
+static inline int is_level_sensitive(int irq)
 {
-       int irq, cas_irq;
-       unsigned long bits;
-       cas_irq = 0;
-       /*
-        * Only report the status of those interrupts that are actually
-        * enabled.
-        */
-
-#if (NR_UICS > 2)
-       bits = mfdcr(DCRN_UIC_MSR(UICB));
-#else
-       bits = mfdcr(DCRN_UIC_MSR(UIC0));
-#endif
-#if (NR_UICS > 2)
-       if (bits & UICB_UIC0NC) {
-               bits = mfdcr(DCRN_UIC_MSR(UIC0));
-               irq = 32 - ffs(bits);
-       } else if (bits & UICB_UIC1NC) {
-               bits = mfdcr(DCRN_UIC_MSR(UIC1));
-               irq = 64 - ffs(bits);
-       } else if (bits & UICB_UIC2NC) {
-               bits = mfdcr(DCRN_UIC_MSR(UIC2));
-               irq = 96 - ffs(bits);
-       } else {
-               irq = -1;
-       }
-#elif (NR_UICS > 1)
-       if (bits & UIC_CASCADE_MASK) {
-               bits = mfdcr(DCRN_UIC_MSR(UIC1));
-               cas_irq = 32 - ffs(bits);
-               irq = 32 + cas_irq;
-       } else {
-               irq = 32 - ffs(bits);
-               if (irq == 32)
-                       irq = -1;
-       }
-#else
-       /*
-        * Walk through the interrupts from highest priority to lowest, and
-        * report the first pending interrupt found.
-        * We want PPC, not C bit numbering, so just subtract the ffs()
-        * result from 32.
-        */
-       irq = 32 - ffs(bits);
-#endif
-       if (irq == (NR_UIC_IRQS * NR_UICS))
-               irq = -1;
-
-#ifdef UIC_DEBUG
-       printk("ppc4xx_pic_get_irq - irq %d bit 0x%x\n", irq, bits);
-#endif
-
-       return (irq);
+       u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
+       return (tr & IRQ_MASK_UICx(irq)) == 0;
 }
-#endif
 
-void __init
-ppc4xx_extpic_init(void)
+void __init ppc4xx_pic_init(void)
 {
-       /* set polarity
-        * 1 = default/pos/rising  , 0= neg/falling internal
-        * 1 = neg/falling , 0= pos/rising external
-        * Sense
-        * 0 = default level internal
-        * 0 = level, 1 = edge external
-        */
-
-       unsigned int sense, irq;
-       int bit, word;
-       unsigned long ppc_cached_sense_mask[NR_MASK_WORDS];
-       unsigned long ppc_cached_pol_mask[NR_MASK_WORDS];
-       ppc_cached_sense_mask[0] = 0;
-       ppc_cached_sense_mask[1] = 0;
-       ppc_cached_sense_mask[2] = 0;
-       ppc_cached_pol_mask[0] = 0;
-       ppc_cached_pol_mask[1] = 0;
-       ppc_cached_pol_mask[2] = 0;
-
-       for (irq = 0; irq < NR_IRQS; irq++) {
-
-               bit = irq & 0x1f;
-               word = irq >> 5;
-
-               sense =
-                   (irq <
-                    ibm4xxPIC_NumInitSenses) ? ibm4xxPIC_InitSenses[irq] : 3;
-#ifdef PPC4xx_PIC_DEBUG
-               printk("PPC4xx_picext %d word:%x bit:%x sense:%x", irq, word,
-                      bit, sense);
-#endif
-               ppc_cached_sense_mask[word] |=
-                   (~sense & IRQ_SENSE_MASK) << (31 - bit);
-               ppc_cached_pol_mask[word] |=
-                   ((sense & IRQ_POLARITY_MASK) >> 1) << (31 - bit);
-               switch (word) {
-               case 0:
-#ifdef PPC4xx_PIC_DEBUG
-                       printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC0)));
-                       printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC0)));
-#endif
-                       /* polarity  setting */
-                       mtdcr(DCRN_UIC_PR(UIC0), ppc_cached_pol_mask[word]);
-
-                       /* Level setting */
-                       mtdcr(DCRN_UIC_TR(UIC0), ppc_cached_sense_mask[word]);
-
-                       break;
-               case 1:
-#ifdef PPC4xx_PIC_DEBUG
-                       printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC1)));
-                       printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC1)));
-#endif
-                       /* polarity  setting */
-                       mtdcr(DCRN_UIC_PR(UIC1), ppc_cached_pol_mask[word]);
-
-                       /* Level setting */
-                       mtdcr(DCRN_UIC_TR(UIC1), ppc_cached_sense_mask[word]);
-
-                       break;
-               case 2:
-#ifdef PPC4xx_PIC_DEBUG
-                       printk("Pol %x ", mfdcr(DCRN_UIC_PR(UIC2)));
-                       printk("Level %x\n", mfdcr(DCRN_UIC_TR(UIC2)));
-#endif
-                       /* polarity  setting */
-                       mtdcr(DCRN_UIC_PR(UIC2), ppc_cached_pol_mask[word]);
-
-                       /* Level setting */
-                       mtdcr(DCRN_UIC_TR(UIC2), ppc_cached_sense_mask[word]);
-
-                       break;
+       int i;
+       unsigned char* eirqs = ppc4xx_uic_ext_irq_cfg;
+
+       for (i = 0; i < NR_UICS; ++i){
+               int base = __uic[i].base;
+
+               /* Disable everything by default */
+               ppc_cached_irq_mask[i] = 0;
+               mtdcr(DCRN_UIC_ER(base), 0);
+
+               /* We don't use critical interrupts */
+               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;
+                       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;
+                       tr |= p->triggering & ~mask;
+
+                       /* Merge external IRQs settings if board port
+                        * provided them
+                        */
+                       if (eirqs && mask){
+                               pr &= ~mask;
+                               tr &= ~mask;
+                               while (mask){
+                                       /* Extract current external IRQ mask */
+                                       u32 eirq_mask = 1 << __ilog2(mask);
+
+                                       if (!(*eirqs & IRQ_SENSE_LEVEL))
+                                               tr |= eirq_mask;
+
+                                       if (*eirqs & IRQ_POLARITY_POSITIVE)
+                                               pr |= eirq_mask;
+
+                                       mask &= ~eirq_mask;
+                                       ++eirqs;
+                               }
+                       }
+                       mtdcr(DCRN_UIC_PR(base), pr);
+                       mtdcr(DCRN_UIC_TR(base), tr);
                }
+
+               /* ACK any pending interrupts to prevent false
+                * triggering after first enable
+                */
+               mtdcr(DCRN_UIC_SR(base), 0xffffffff);
        }
 
-}
-void __init
-ppc4xx_pic_init(void)
-{
-       /*
-        * Disable all external interrupts until they are
-        * explicity requested.
+       /* Perform optional implementation specific setup
+        * (e.g. enable cascade interrupts for multi-UIC configurations)
         */
-       ppc_cached_irq_mask[0] = 0;
-       ppc_cached_irq_mask[1] = 0;
-       ppc_cached_irq_mask[2] = 0;
-
-#if defined CONFIG_403
-       mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
+       ppc4xx_pic_impl_init();
 
-       ppc4xx_pic = &ppc403_aic;
-       ppc_md.get_irq = ppc403_pic_get_irq;
-#else
-#if  (NR_UICS > 2)
-       mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
-       mtdcr(DCRN_UIC_CR(UICB), 0);
-
-       mtdcr(DCRN_UIC_ER(UIC2), ppc_cached_irq_mask[2]);
-       mtdcr(DCRN_UIC_CR(UIC2), 0);
-
-#endif
-#if  (NR_UICS > 1)
-#if  (NR_UICS == 2)
-       /* enable cascading interrupt */
-       ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC);
-#endif
-       mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]);
-       mtdcr(DCRN_UIC_CR(UIC1), 0);
-#endif
-       mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
-       mtdcr(DCRN_UIC_CR(UIC0), 0);
-
-       if (ibm4xxPIC_InitSenses != NULL)
-               ppc4xx_extpic_init();
-
-       /* Clear any pending interrupts */
-#if (NR_UICS > 2)
-       mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
-       mtdcr(DCRN_UIC_SR(UIC2), 0xffffffff);
-#endif
-#if (NR_UICS > 1)
-       mtdcr(DCRN_UIC_SR(UIC1), 0xffffffff);
-#endif
-       mtdcr(DCRN_UIC_SR(UIC0), 0xffffffff);
+       /* Attach low-level handlers */
+       for (i = 0; i < (NR_UICS << 5); ++i){
+               irq_desc[i].handler = &__uic[i >> 5].decl;
+               if (is_level_sensitive(i))
+                       irq_desc[i].status |= IRQ_LEVEL;
+       }
 
-       ppc4xx_pic = &ppc4xx_uic;
        ppc_md.get_irq = ppc4xx_pic_get_irq;
-#endif
 }