]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
ARM: at91: add AIC5 support
authorLudovic Desroches <ludovic.desroches@atmel.com>
Wed, 30 May 2012 08:01:09 +0000 (10:01 +0200)
committerNicolas Ferre <nicolas.ferre@atmel.com>
Mon, 2 Jul 2012 12:31:00 +0000 (14:31 +0200)
The number of lines of AIC5 has increased from 32 to 128. Due to this
increase, a source select register has been introduced for the interrupt
line selection. Moreover, register mapping has been changed. For that reasons,
we need some dedicated callbacks for AIC5.
Power management is also concerned by these changes. On suspend, we can't get
the whole interrupt mask register as before, we have to read this register 128
times. To reduce this overhead, a snapshot of the whole IMR is maintained.

Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
arch/arm/mach-at91/generic.h
arch/arm/mach-at91/include/mach/at91_aic.h
arch/arm/mach-at91/irq.c

index 0a60bf837037dd67382163c30f3290ed30acb9ae..f49650677653a0f0488e6c64346fcf07e46ae555 100644 (file)
@@ -29,6 +29,8 @@ extern void __init at91x40_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 extern int  __init at91_aic_of_init(struct device_node *node,
                                    struct device_node *parent);
+extern int  __init at91_aic5_of_init(struct device_node *node,
+                                   struct device_node *parent);
 
 
  /* Timer */
index fd42a85b7eb18ac4dc7e3b2e01ea1d19c14eaf50..eaea66197fa17f606e8f5d2228b5efa61e936c86 100644 (file)
@@ -30,11 +30,16 @@ extern void __iomem *at91_aic_base;
 
 /* Number of irq lines managed by AIC */
 #define NR_AIC_IRQS    32
+#define NR_AIC5_IRQS   128
+
+#define AT91_AIC5_SSR          0x0                     /* Source Select Register [AIC5] */
+#define        AT91_AIC5_INTSEL_MSK    (0x7f << 0)             /* Interrupt Line Selection Mask */
 
 #define AT91_AIC_IRQ_MIN_PRIORITY      0
 #define AT91_AIC_IRQ_MAX_PRIORITY      7
 
 #define AT91_AIC_SMR(n)                ((n) * 4)               /* Source Mode Registers 0-31 */
+#define AT91_AIC5_SMR          0x4                     /* Source Mode Register [AIC5] */
 #define                AT91_AIC_PRIOR          (7 << 0)                /* Priority Level */
 #define                AT91_AIC_SRCTYPE        (3 << 5)                /* Interrupt Source Type */
 #define                        AT91_AIC_SRCTYPE_LOW            (0 << 5)
@@ -43,31 +48,52 @@ extern void __iomem *at91_aic_base;
 #define                        AT91_AIC_SRCTYPE_RISING         (3 << 5)
 
 #define AT91_AIC_SVR(n)                (0x80 + ((n) * 4))      /* Source Vector Registers 0-31 */
+#define AT91_AIC5_SVR          0x8                     /* Source Vector Register [AIC5] */
 #define AT91_AIC_IVR           0x100                   /* Interrupt Vector Register */
+#define AT91_AIC5_IVR          0x10                    /* Interrupt Vector Register [AIC5] */
 #define AT91_AIC_FVR           0x104                   /* Fast Interrupt Vector Register */
+#define AT91_AIC5_FVR          0x14                    /* Fast Interrupt Vector Register [AIC5] */
 #define AT91_AIC_ISR           0x108                   /* Interrupt Status Register */
+#define AT91_AIC5_ISR          0x18                    /* Interrupt Status Register [AIC5] */
 #define                AT91_AIC_IRQID          (0x1f << 0)             /* Current Interrupt Identifier */
 
 #define AT91_AIC_IPR           0x10c                   /* Interrupt Pending Register */
+#define AT91_AIC5_IPR0         0x20                    /* Interrupt Pending Register 0 [AIC5] */
+#define AT91_AIC5_IPR1         0x24                    /* Interrupt Pending Register 1 [AIC5] */
+#define AT91_AIC5_IPR2         0x28                    /* Interrupt Pending Register 2 [AIC5] */
+#define AT91_AIC5_IPR3         0x2c                    /* Interrupt Pending Register 3 [AIC5] */
 #define AT91_AIC_IMR           0x110                   /* Interrupt Mask Register */
+#define AT91_AIC5_IMR          0x30                    /* Interrupt Mask Register [AIC5] */
 #define AT91_AIC_CISR          0x114                   /* Core Interrupt Status Register */
+#define AT91_AIC5_CISR         0x34                    /* Core Interrupt Status Register [AIC5] */
 #define                AT91_AIC_NFIQ           (1 << 0)                /* nFIQ Status */
 #define                AT91_AIC_NIRQ           (1 << 1)                /* nIRQ Status */
 
 #define AT91_AIC_IECR          0x120                   /* Interrupt Enable Command Register */
+#define AT91_AIC5_IECR         0x40                    /* Interrupt Enable Command Register [AIC5] */
 #define AT91_AIC_IDCR          0x124                   /* Interrupt Disable Command Register */
+#define AT91_AIC5_IDCR         0x44                    /* Interrupt Disable Command Register [AIC5] */
 #define AT91_AIC_ICCR          0x128                   /* Interrupt Clear Command Register */
+#define AT91_AIC5_ICCR         0x48                    /* Interrupt Clear Command Register [AIC5] */
 #define AT91_AIC_ISCR          0x12c                   /* Interrupt Set Command Register */
+#define AT91_AIC5_ISCR         0x4c                    /* Interrupt Set Command Register [AIC5] */
 #define AT91_AIC_EOICR         0x130                   /* End of Interrupt Command Register */
+#define AT91_AIC5_EOICR                0x38                    /* End of Interrupt Command Register [AIC5] */
 #define AT91_AIC_SPU           0x134                   /* Spurious Interrupt Vector Register */
+#define AT91_AIC5_SPU          0x3c                    /* Spurious Interrupt Vector Register [AIC5] */
 #define AT91_AIC_DCR           0x138                   /* Debug Control Register */
+#define AT91_AIC5_DCR          0x6c                    /* Debug Control Register [AIC5] */
 #define                AT91_AIC_DCR_PROT       (1 << 0)                /* Protection Mode */
 #define                AT91_AIC_DCR_GMSK       (1 << 1)                /* General Mask */
 
 #define AT91_AIC_FFER          0x140                   /* Fast Forcing Enable Register [SAM9 only] */
+#define AT91_AIC5_FFER         0x50                    /* Fast Forcing Enable Register [AIC5] */
 #define AT91_AIC_FFDR          0x144                   /* Fast Forcing Disable Register [SAM9 only] */
+#define AT91_AIC5_FFDR         0x54                    /* Fast Forcing Disable Register [AIC5] */
 #define AT91_AIC_FFSR          0x148                   /* Fast Forcing Status Register [SAM9 only] */
+#define AT91_AIC5_FFSR         0x58                    /* Fast Forcing Status Register [AIC5] */
 
 void at91_aic_handle_irq(struct pt_regs *regs);
+void at91_aic5_handle_irq(struct pt_regs *regs);
 
 #endif
index 75ca2f44c78e78f6aed5198713680d3b84e993e0..c5eaaa060bd8a8f212f553c4e058a2d0627f3f3a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/bitmap.h>
 #include <linux/types.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 void __iomem *at91_aic_base;
 static struct irq_domain *at91_aic_domain;
 static struct device_node *at91_aic_np;
+static unsigned int n_irqs = NR_AIC_IRQS;
+static unsigned long at91_aic_caps = 0;
 static unsigned int *at91_aic_irq_priorities;
 
-asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
+/* AIC5 introduces a Source Select Register */
+#define AT91_AIC_CAP_AIC5      (1 << 0)
+#define has_aic5()             (at91_aic_caps & AT91_AIC_CAP_AIC5)
+
+#ifdef CONFIG_PM
+
+static unsigned long *wakeups;
+static unsigned long *backups;
+
+#define set_backup(bit) set_bit(bit, backups)
+#define clear_backup(bit) clear_bit(bit, backups)
+
+static int at91_aic_pm_init(void)
+{
+       backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
+       if (!backups)
+               return -ENOMEM;
+
+       wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
+       if (!wakeups) {
+               kfree(backups);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int at91_aic_set_wake(struct irq_data *d, unsigned value)
+{
+       if (unlikely(d->hwirq >= n_irqs))
+               return -EINVAL;
+
+       if (value)
+               set_bit(d->hwirq, wakeups);
+       else
+               clear_bit(d->hwirq, wakeups);
+
+       return 0;
+}
+
+void at91_irq_suspend(void)
+{
+       int i = 0, bit;
+
+       if (has_aic5()) {
+               /* disable enabled irqs */
+               while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IDCR, 1);
+                       i = bit;
+               }
+               /* enable wakeup irqs */
+               i = 0;
+               while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IECR, 1);
+                       i = bit;
+               }
+       } else {
+               at91_aic_write(AT91_AIC_IDCR, *backups);
+               at91_aic_write(AT91_AIC_IECR, *wakeups);
+       }
+}
+
+void at91_irq_resume(void)
+{
+       int i = 0, bit;
+
+       if (has_aic5()) {
+               /* disable wakeup irqs */
+               while ((bit = find_next_bit(wakeups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IDCR, 1);
+                       i = bit;
+               }
+               /* enable irqs disabled for suspend */
+               i = 0;
+               while ((bit = find_next_bit(backups, n_irqs, i)) < n_irqs) {
+                       at91_aic_write(AT91_AIC5_SSR,
+                                      bit & AT91_AIC5_INTSEL_MSK);
+                       at91_aic_write(AT91_AIC5_IECR, 1);
+                       i = bit;
+               }
+       } else {
+               at91_aic_write(AT91_AIC_IDCR, *wakeups);
+               at91_aic_write(AT91_AIC_IECR, *backups);
+       }
+}
+
+#else
+static inline int at91_aic_pm_init(void)
+{
+       return 0;
+}
+
+#define set_backup(bit)
+#define clear_backup(bit)
+#define at91_aic_set_wake      NULL
+
+#endif /* CONFIG_PM */
+
+asmlinkage void __exception_irq_entry
+at91_aic_handle_irq(struct pt_regs *regs)
 {
        u32 irqnr;
        u32 irqstat;
@@ -66,16 +174,53 @@ asmlinkage void __exception_irq_entry at91_aic_handle_irq(struct pt_regs *regs)
                handle_IRQ(irqnr, regs);
 }
 
+asmlinkage void __exception_irq_entry
+at91_aic5_handle_irq(struct pt_regs *regs)
+{
+       u32 irqnr;
+       u32 irqstat;
+
+       irqnr = at91_aic_read(AT91_AIC5_IVR);
+       irqstat = at91_aic_read(AT91_AIC5_ISR);
+
+       if (!irqstat)
+               at91_aic_write(AT91_AIC5_EOICR, 0);
+       else
+               handle_IRQ(irqnr, regs);
+}
+
 static void at91_aic_mask_irq(struct irq_data *d)
 {
        /* Disable interrupt on AIC */
        at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
+       /* Update ISR cache */
+       clear_backup(d->hwirq);
+}
+
+static void __maybe_unused at91_aic5_mask_irq(struct irq_data *d)
+{
+       /* Disable interrupt on AIC5 */
+       at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
+       at91_aic_write(AT91_AIC5_IDCR, 1);
+       /* Update ISR cache */
+       clear_backup(d->hwirq);
 }
 
 static void at91_aic_unmask_irq(struct irq_data *d)
 {
        /* Enable interrupt on AIC */
        at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
+       /* Update ISR cache */
+       set_backup(d->hwirq);
+}
+
+static void __maybe_unused at91_aic5_unmask_irq(struct irq_data *d)
+{
+       /* Enable interrupt on AIC5 */
+       at91_aic_write(AT91_AIC5_SSR, d->hwirq & AT91_AIC5_INTSEL_MSK);
+       at91_aic_write(AT91_AIC5_IECR, 1);
+       /* Update ISR cache */
+       set_backup(d->hwirq);
 }
 
 static void at91_aic_eoi(struct irq_data *d)
@@ -87,13 +232,18 @@ static void at91_aic_eoi(struct irq_data *d)
        at91_aic_write(AT91_AIC_EOICR, 0);
 }
 
-unsigned int at91_extern_irq;
+static void __maybe_unused at91_aic5_eoi(struct irq_data *d)
+{
+       at91_aic_write(AT91_AIC5_EOICR, 0);
+}
 
-#define is_extern_irq(hwirq) ((1 << (hwirq)) & at91_extern_irq)
+unsigned long *at91_extern_irq;
 
-static int at91_aic_set_type(struct irq_data *d, unsigned type)
+#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
+
+static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
 {
-       unsigned int smr, srctype;
+       int srctype;
 
        switch (type) {
        case IRQ_TYPE_LEVEL_HIGH:
@@ -106,58 +256,44 @@ static int at91_aic_set_type(struct irq_data *d, unsigned type)
                if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_LOW;
                else
-                       return -EINVAL;
+                       srctype = -EINVAL;
                break;
        case IRQ_TYPE_EDGE_FALLING:
                if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq))               /* only supported on external interrupts */
                        srctype = AT91_AIC_SRCTYPE_FALLING;
                else
-                       return -EINVAL;
+                       srctype = -EINVAL;
                break;
        default:
-               return -EINVAL;
+               srctype = -EINVAL;
        }
 
-       smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
-       at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
-       return 0;
+       return srctype;
 }
 
-#ifdef CONFIG_PM
-
-static u32 wakeups;
-static u32 backups;
-
-static int at91_aic_set_wake(struct irq_data *d, unsigned value)
+static int at91_aic_set_type(struct irq_data *d, unsigned type)
 {
-       if (unlikely(d->hwirq >= NR_AIC_IRQS))
-               return -EINVAL;
-
-       if (value)
-               wakeups |= (1 << d->hwirq);
-       else
-               wakeups &= ~(1 << d->hwirq);
+       unsigned int smr;
+       int srctype;
+
+       srctype = at91_aic_compute_srctype(d, type);
+       if (srctype < 0)
+               return srctype;
+
+       if (has_aic5()) {
+               at91_aic_write(AT91_AIC5_SSR,
+                              d->hwirq & AT91_AIC5_INTSEL_MSK);
+               smr = at91_aic_read(AT91_AIC5_SMR) & ~AT91_AIC_SRCTYPE;
+               at91_aic_write(AT91_AIC5_SMR, smr | srctype);
+       } else {
+               smr = at91_aic_read(AT91_AIC_SMR(d->hwirq))
+                     & ~AT91_AIC_SRCTYPE;
+               at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
+       }
 
        return 0;
 }
 
-void at91_irq_suspend(void)
-{
-       backups = at91_aic_read(AT91_AIC_IMR);
-       at91_aic_write(AT91_AIC_IDCR, backups);
-       at91_aic_write(AT91_AIC_IECR, wakeups);
-}
-
-void at91_irq_resume(void)
-{
-       at91_aic_write(AT91_AIC_IDCR, wakeups);
-       at91_aic_write(AT91_AIC_IECR, backups);
-}
-
-#else
-#define at91_aic_set_wake      NULL
-#endif
-
 static struct irq_chip at91_aic_chip = {
        .name           = "AIC",
        .irq_mask       = at91_aic_mask_irq,
@@ -193,6 +329,35 @@ static void __init at91_aic_hw_init(unsigned int spu_vector)
        at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
 }
 
+static void __init __maybe_unused at91_aic5_hw_init(unsigned int spu_vector)
+{
+       int i;
+
+       /*
+        * Perform 8 End Of Interrupt Command to make sure AIC
+        * will not Lock out nIRQ
+        */
+       for (i = 0; i < 8; i++)
+               at91_aic_write(AT91_AIC5_EOICR, 0);
+
+       /*
+        * Spurious Interrupt ID in Spurious Vector Register.
+        * When there is no current interrupt, the IRQ Vector Register
+        * reads the value stored in AIC_SPU
+        */
+       at91_aic_write(AT91_AIC5_SPU, spu_vector);
+
+       /* No debugging in AIC: Debug (Protect) Control Register */
+       at91_aic_write(AT91_AIC5_DCR, 0);
+
+       /* Disable and clear all interrupts initially */
+       for (i = 0; i < n_irqs; i++) {
+               at91_aic_write(AT91_AIC5_SSR, i & AT91_AIC5_INTSEL_MSK);
+               at91_aic_write(AT91_AIC5_IDCR, 1);
+               at91_aic_write(AT91_AIC5_ICCR, 1);
+       }
+}
+
 #if defined(CONFIG_OF)
 static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
                                                        irq_hw_number_t hw)
@@ -210,13 +375,31 @@ static int at91_aic_irq_map(struct irq_domain *h, unsigned int virq,
        return 0;
 }
 
+static int at91_aic5_irq_map(struct irq_domain *h, unsigned int virq,
+               irq_hw_number_t hw)
+{
+       at91_aic_write(AT91_AIC5_SSR, hw & AT91_AIC5_INTSEL_MSK);
+
+       /* Put virq number in Source Vector Register */
+       at91_aic_write(AT91_AIC5_SVR, virq);
+
+       /* Active Low interrupt, with priority */
+       at91_aic_write(AT91_AIC5_SMR,
+                      AT91_AIC_SRCTYPE_LOW | at91_aic_irq_priorities[hw]);
+
+       irq_set_chip_and_handler(virq, &at91_aic_chip, handle_fasteoi_irq);
+       set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+       return 0;
+}
+
 static int at91_aic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr,
                                const u32 *intspec, unsigned int intsize,
                                irq_hw_number_t *out_hwirq, unsigned int *out_type)
 {
        if (WARN_ON(intsize < 3))
                return -EINVAL;
-       if (WARN_ON(intspec[0] >= NR_AIC_IRQS))
+       if (WARN_ON(intspec[0] >= n_irqs))
                return -EINVAL;
        if (WARN_ON((intspec[2] < AT91_AIC_IRQ_MIN_PRIORITY)
                    || (intspec[2] > AT91_AIC_IRQ_MAX_PRIORITY)))
@@ -234,14 +417,24 @@ static struct irq_domain_ops at91_aic_irq_ops = {
        .xlate  = at91_aic_irq_domain_xlate,
 };
 
-int __init at91_aic_of_init(struct device_node *node,
-                                    struct device_node *parent)
+int __init at91_aic_of_common_init(struct device_node *node,
+                                   struct device_node *parent)
 {
        struct property *prop;
        const __be32 *p;
        u32 val;
 
-       at91_aic_irq_priorities = kzalloc(NR_AIC_IRQS
+       at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
+                                 * sizeof(*at91_extern_irq), GFP_KERNEL);
+       if (!at91_extern_irq)
+               return -ENOMEM;
+
+       if (at91_aic_pm_init()) {
+               kfree(at91_extern_irq);
+               return -ENOMEM;
+       }
+
+       at91_aic_irq_priorities = kzalloc(n_irqs
                                          * sizeof(*at91_aic_irq_priorities),
                                          GFP_KERNEL);
        if (!at91_aic_irq_priorities)
@@ -250,22 +443,56 @@ int __init at91_aic_of_init(struct device_node *node,
        at91_aic_base = of_iomap(node, 0);
        at91_aic_np = node;
 
-       at91_aic_domain = irq_domain_add_linear(at91_aic_np, NR_AIC_IRQS,
+       at91_aic_domain = irq_domain_add_linear(at91_aic_np, n_irqs,
                                                &at91_aic_irq_ops, NULL);
        if (!at91_aic_domain)
                panic("Unable to add AIC irq domain (DT)\n");
 
-       at91_extern_irq = 0;
        of_property_for_each_u32(node, "atmel,external-irqs", prop, p, val) {
-               if (val > 31)
-                       pr_warn("AIC: external irq %d > 31 skip it\n", val);
+               if (val >= n_irqs)
+                       pr_warn("AIC: external irq %d >= %d skip it\n",
+                               val, n_irqs);
                else
-                       at91_extern_irq |= (1 << val);
+                       set_bit(val, at91_extern_irq);
        }
 
        irq_set_default_host(at91_aic_domain);
 
-       at91_aic_hw_init(NR_AIC_IRQS);
+       return 0;
+}
+
+int __init at91_aic_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       int err;
+
+       err = at91_aic_of_common_init(node, parent);
+       if (err)
+               return err;
+
+       at91_aic_hw_init(n_irqs);
+
+       return 0;
+}
+
+int __init at91_aic5_of_init(struct device_node *node,
+                                    struct device_node *parent)
+{
+       int err;
+
+       at91_aic_caps |= AT91_AIC_CAP_AIC5;
+       n_irqs = NR_AIC5_IRQS;
+       at91_aic_chip.irq_ack           = at91_aic5_mask_irq;
+       at91_aic_chip.irq_mask          = at91_aic5_mask_irq;
+       at91_aic_chip.irq_unmask        = at91_aic5_unmask_irq;
+       at91_aic_chip.irq_eoi           = at91_aic5_eoi;
+       at91_aic_irq_ops.map            = at91_aic5_irq_map;
+
+       err = at91_aic_of_common_init(node, parent);
+       if (err)
+               return err;
+
+       at91_aic5_hw_init(n_irqs);
 
        return 0;
 }
@@ -274,22 +501,25 @@ int __init at91_aic_of_init(struct device_node *node,
 /*
  * Initialize the AIC interrupt controller.
  */
-void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
+void __init at91_aic_init(unsigned int *priority)
 {
        unsigned int i;
        int irq_base;
 
+       if (at91_aic_pm_init())
+               panic("Unable to allocate bit maps\n");
+
        at91_aic_base = ioremap(AT91_AIC, 512);
        if (!at91_aic_base)
                panic("Unable to ioremap AIC registers\n");
 
        /* Add irq domain for AIC */
-       irq_base = irq_alloc_descs(-1, 0, NR_AIC_IRQS, 0);
+       irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
        if (irq_base < 0) {
                WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
                irq_base = 0;
        }
-       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, NR_AIC_IRQS,
+       at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
                                                irq_base, 0,
                                                &irq_domain_simple_ops, NULL);
 
@@ -302,15 +532,14 @@ void __init at91_aic_init(unsigned int priority[NR_AIC_IRQS])
         * The IVR is used by macro get_irqnr_and_base to read and verify.
         * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
         */
-       for (i = 0; i < NR_AIC_IRQS; i++) {
+       for (i = 0; i < n_irqs; i++) {
                /* Put hardware irq number in Source Vector Register: */
                at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
                /* Active Low interrupt, with the specified priority */
                at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
-
                irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
        }
 
-       at91_aic_hw_init(NR_AIC_IRQS);
+       at91_aic_hw_init(n_irqs);
 }