1171bb2f1SJohn Crispin /* 2171bb2f1SJohn Crispin * This program is free software; you can redistribute it and/or modify it 3171bb2f1SJohn Crispin * under the terms of the GNU General Public License version 2 as published 4171bb2f1SJohn Crispin * by the Free Software Foundation. 5171bb2f1SJohn Crispin * 697b92108SJohn Crispin * Copyright (C) 2010 John Crispin <john@phrozen.org> 7171bb2f1SJohn Crispin * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 8171bb2f1SJohn Crispin */ 9171bb2f1SJohn Crispin 10171bb2f1SJohn Crispin #include <linux/interrupt.h> 11171bb2f1SJohn Crispin #include <linux/ioport.h> 123645da02SJohn Crispin #include <linux/sched.h> 133645da02SJohn Crispin #include <linux/irqdomain.h> 143645da02SJohn Crispin #include <linux/of_platform.h> 153645da02SJohn Crispin #include <linux/of_address.h> 163645da02SJohn Crispin #include <linux/of_irq.h> 17171bb2f1SJohn Crispin 18171bb2f1SJohn Crispin #include <asm/bootinfo.h> 19171bb2f1SJohn Crispin #include <asm/irq_cpu.h> 20171bb2f1SJohn Crispin 21171bb2f1SJohn Crispin #include <lantiq_soc.h> 22171bb2f1SJohn Crispin #include <irq.h> 23171bb2f1SJohn Crispin 243645da02SJohn Crispin /* register definitions - internal irqs */ 25f0dd3001SPetr Cvek #define LTQ_ICU_ISR 0x0000 26f0dd3001SPetr Cvek #define LTQ_ICU_IER 0x0008 27f0dd3001SPetr Cvek #define LTQ_ICU_IOSR 0x0010 28f0dd3001SPetr Cvek #define LTQ_ICU_IRSR 0x0018 29f0dd3001SPetr Cvek #define LTQ_ICU_IMR 0x0020 30171bb2f1SJohn Crispin 31*85cf2c37SPetr Cvek #define LTQ_ICU_IM_SIZE 0x28 32*85cf2c37SPetr Cvek 333645da02SJohn Crispin /* register definitions - external irqs */ 34171bb2f1SJohn Crispin #define LTQ_EIU_EXIN_C 0x0000 35171bb2f1SJohn Crispin #define LTQ_EIU_EXIN_INIC 0x0004 3626365625SJohn Crispin #define LTQ_EIU_EXIN_INC 0x0008 37171bb2f1SJohn Crispin #define LTQ_EIU_EXIN_INEN 0x000C 38171bb2f1SJohn Crispin 3926365625SJohn Crispin /* number of external interrupts */ 40171bb2f1SJohn Crispin #define MAX_EIU 6 41171bb2f1SJohn Crispin 4259c11579SJohn Crispin /* the performance counter */ 4359c11579SJohn Crispin #define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) 4459c11579SJohn Crispin 453645da02SJohn Crispin /* 463645da02SJohn Crispin * irqs generated by devices attached to the EBU need to be acked in 47171bb2f1SJohn Crispin * a special manner 48171bb2f1SJohn Crispin */ 49171bb2f1SJohn Crispin #define LTQ_ICU_EBU_IRQ 22 50171bb2f1SJohn Crispin 51*85cf2c37SPetr Cvek #define ltq_icu_w32(vpe, m, x, y) \ 52*85cf2c37SPetr Cvek ltq_w32((x), ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (y)) 53*85cf2c37SPetr Cvek 54*85cf2c37SPetr Cvek #define ltq_icu_r32(vpe, m, x) \ 55*85cf2c37SPetr Cvek ltq_r32(ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (x)) 56171bb2f1SJohn Crispin 57171bb2f1SJohn Crispin #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) 58171bb2f1SJohn Crispin #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) 59171bb2f1SJohn Crispin 603645da02SJohn Crispin /* we have a cascade of 8 irqs */ 613645da02SJohn Crispin #define MIPS_CPU_IRQ_CASCADE 8 623645da02SJohn Crispin 633645da02SJohn Crispin static int exin_avail; 64fe46e503SJohn Crispin static u32 ltq_eiu_irq[MAX_EIU]; 65*85cf2c37SPetr Cvek static void __iomem *ltq_icu_membase[NR_CPUS]; 66171bb2f1SJohn Crispin static void __iomem *ltq_eiu_membase; 67c2c9c788SJohn Crispin static struct irq_domain *ltq_domain; 68*85cf2c37SPetr Cvek static DEFINE_SPINLOCK(ltq_eiu_lock); 69*85cf2c37SPetr Cvek static DEFINE_RAW_SPINLOCK(ltq_icu_lock); 70a669efc4SAndrew Bresticker static int ltq_perfcount_irq; 71171bb2f1SJohn Crispin 7226365625SJohn Crispin int ltq_eiu_get_irq(int exin) 7326365625SJohn Crispin { 7426365625SJohn Crispin if (exin < exin_avail) 75fe46e503SJohn Crispin return ltq_eiu_irq[exin]; 7626365625SJohn Crispin return -1; 7726365625SJohn Crispin } 7826365625SJohn Crispin 79171bb2f1SJohn Crispin void ltq_disable_irq(struct irq_data *d) 80171bb2f1SJohn Crispin { 8139588164SPetr Cvek unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 8239588164SPetr Cvek unsigned long im = offset / INT_NUM_IM_OFFSET; 83*85cf2c37SPetr Cvek unsigned long flags; 84*85cf2c37SPetr Cvek int vpe; 85171bb2f1SJohn Crispin 863645da02SJohn Crispin offset %= INT_NUM_IM_OFFSET; 87*85cf2c37SPetr Cvek 88*85cf2c37SPetr Cvek raw_spin_lock_irqsave(<q_icu_lock, flags); 89*85cf2c37SPetr Cvek for_each_present_cpu(vpe) { 90*85cf2c37SPetr Cvek ltq_icu_w32(vpe, im, 91*85cf2c37SPetr Cvek ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 92f0dd3001SPetr Cvek LTQ_ICU_IER); 93171bb2f1SJohn Crispin } 94*85cf2c37SPetr Cvek raw_spin_unlock_irqrestore(<q_icu_lock, flags); 95*85cf2c37SPetr Cvek } 96171bb2f1SJohn Crispin 97171bb2f1SJohn Crispin void ltq_mask_and_ack_irq(struct irq_data *d) 98171bb2f1SJohn Crispin { 9939588164SPetr Cvek unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 10039588164SPetr Cvek unsigned long im = offset / INT_NUM_IM_OFFSET; 101*85cf2c37SPetr Cvek unsigned long flags; 102*85cf2c37SPetr Cvek int vpe; 103171bb2f1SJohn Crispin 1043645da02SJohn Crispin offset %= INT_NUM_IM_OFFSET; 105*85cf2c37SPetr Cvek 106*85cf2c37SPetr Cvek raw_spin_lock_irqsave(<q_icu_lock, flags); 107*85cf2c37SPetr Cvek for_each_present_cpu(vpe) { 108*85cf2c37SPetr Cvek ltq_icu_w32(vpe, im, 109*85cf2c37SPetr Cvek ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 110f0dd3001SPetr Cvek LTQ_ICU_IER); 111*85cf2c37SPetr Cvek ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 112*85cf2c37SPetr Cvek } 113*85cf2c37SPetr Cvek raw_spin_unlock_irqrestore(<q_icu_lock, flags); 114171bb2f1SJohn Crispin } 115171bb2f1SJohn Crispin 116171bb2f1SJohn Crispin static void ltq_ack_irq(struct irq_data *d) 117171bb2f1SJohn Crispin { 11839588164SPetr Cvek unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 11939588164SPetr Cvek unsigned long im = offset / INT_NUM_IM_OFFSET; 120*85cf2c37SPetr Cvek unsigned long flags; 121*85cf2c37SPetr Cvek int vpe; 122171bb2f1SJohn Crispin 1233645da02SJohn Crispin offset %= INT_NUM_IM_OFFSET; 124*85cf2c37SPetr Cvek 125*85cf2c37SPetr Cvek raw_spin_lock_irqsave(<q_icu_lock, flags); 126*85cf2c37SPetr Cvek for_each_present_cpu(vpe) { 127*85cf2c37SPetr Cvek ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 128*85cf2c37SPetr Cvek } 129*85cf2c37SPetr Cvek raw_spin_unlock_irqrestore(<q_icu_lock, flags); 130171bb2f1SJohn Crispin } 131171bb2f1SJohn Crispin 132171bb2f1SJohn Crispin void ltq_enable_irq(struct irq_data *d) 133171bb2f1SJohn Crispin { 13439588164SPetr Cvek unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 13539588164SPetr Cvek unsigned long im = offset / INT_NUM_IM_OFFSET; 136*85cf2c37SPetr Cvek unsigned long flags; 137*85cf2c37SPetr Cvek int vpe; 138171bb2f1SJohn Crispin 1393645da02SJohn Crispin offset %= INT_NUM_IM_OFFSET; 140*85cf2c37SPetr Cvek 141*85cf2c37SPetr Cvek vpe = cpumask_first(irq_data_get_effective_affinity_mask(d)); 142*85cf2c37SPetr Cvek 143*85cf2c37SPetr Cvek /* This shouldn't be even possible, maybe during CPU hotplug spam */ 144*85cf2c37SPetr Cvek if (unlikely(vpe >= nr_cpu_ids)) 145*85cf2c37SPetr Cvek vpe = smp_processor_id(); 146*85cf2c37SPetr Cvek 147*85cf2c37SPetr Cvek raw_spin_lock_irqsave(<q_icu_lock, flags); 148*85cf2c37SPetr Cvek 149*85cf2c37SPetr Cvek ltq_icu_w32(vpe, im, ltq_icu_r32(vpe, im, LTQ_ICU_IER) | BIT(offset), 150f0dd3001SPetr Cvek LTQ_ICU_IER); 151*85cf2c37SPetr Cvek 152*85cf2c37SPetr Cvek raw_spin_unlock_irqrestore(<q_icu_lock, flags); 153171bb2f1SJohn Crispin } 154171bb2f1SJohn Crispin 15526365625SJohn Crispin static int ltq_eiu_settype(struct irq_data *d, unsigned int type) 15626365625SJohn Crispin { 15726365625SJohn Crispin int i; 158*85cf2c37SPetr Cvek unsigned long flags; 15926365625SJohn Crispin 160f97e5e8eSJohn Crispin for (i = 0; i < exin_avail; i++) { 161fe46e503SJohn Crispin if (d->hwirq == ltq_eiu_irq[i]) { 16226365625SJohn Crispin int val = 0; 16326365625SJohn Crispin int edge = 0; 16426365625SJohn Crispin 16526365625SJohn Crispin switch (type) { 16626365625SJohn Crispin case IRQF_TRIGGER_NONE: 16726365625SJohn Crispin break; 16826365625SJohn Crispin case IRQF_TRIGGER_RISING: 16926365625SJohn Crispin val = 1; 17026365625SJohn Crispin edge = 1; 17126365625SJohn Crispin break; 17226365625SJohn Crispin case IRQF_TRIGGER_FALLING: 17326365625SJohn Crispin val = 2; 17426365625SJohn Crispin edge = 1; 17526365625SJohn Crispin break; 17626365625SJohn Crispin case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: 17726365625SJohn Crispin val = 3; 17826365625SJohn Crispin edge = 1; 17926365625SJohn Crispin break; 18026365625SJohn Crispin case IRQF_TRIGGER_HIGH: 18126365625SJohn Crispin val = 5; 18226365625SJohn Crispin break; 18326365625SJohn Crispin case IRQF_TRIGGER_LOW: 18426365625SJohn Crispin val = 6; 18526365625SJohn Crispin break; 18626365625SJohn Crispin default: 18726365625SJohn Crispin pr_err("invalid type %d for irq %ld\n", 18826365625SJohn Crispin type, d->hwirq); 18926365625SJohn Crispin return -EINVAL; 19026365625SJohn Crispin } 19126365625SJohn Crispin 19226365625SJohn Crispin if (edge) 19326365625SJohn Crispin irq_set_handler(d->hwirq, handle_edge_irq); 19426365625SJohn Crispin 195*85cf2c37SPetr Cvek spin_lock_irqsave(<q_eiu_lock, flags); 196ba1bc0fcSPetr Cvek ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) & 197ba1bc0fcSPetr Cvek (~(7 << (i * 4)))) | (val << (i * 4)), 198ba1bc0fcSPetr Cvek LTQ_EIU_EXIN_C); 199*85cf2c37SPetr Cvek spin_unlock_irqrestore(<q_eiu_lock, flags); 20026365625SJohn Crispin } 20126365625SJohn Crispin } 20226365625SJohn Crispin 20326365625SJohn Crispin return 0; 20426365625SJohn Crispin } 20526365625SJohn Crispin 206171bb2f1SJohn Crispin static unsigned int ltq_startup_eiu_irq(struct irq_data *d) 207171bb2f1SJohn Crispin { 208171bb2f1SJohn Crispin int i; 209171bb2f1SJohn Crispin 210171bb2f1SJohn Crispin ltq_enable_irq(d); 211f97e5e8eSJohn Crispin for (i = 0; i < exin_avail; i++) { 212fe46e503SJohn Crispin if (d->hwirq == ltq_eiu_irq[i]) { 21326365625SJohn Crispin /* by default we are low level triggered */ 21426365625SJohn Crispin ltq_eiu_settype(d, IRQF_TRIGGER_LOW); 215171bb2f1SJohn Crispin /* clear all pending */ 21626365625SJohn Crispin ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i), 21726365625SJohn Crispin LTQ_EIU_EXIN_INC); 218171bb2f1SJohn Crispin /* enable */ 2193645da02SJohn Crispin ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), 220171bb2f1SJohn Crispin LTQ_EIU_EXIN_INEN); 221171bb2f1SJohn Crispin break; 222171bb2f1SJohn Crispin } 223171bb2f1SJohn Crispin } 224171bb2f1SJohn Crispin 225171bb2f1SJohn Crispin return 0; 226171bb2f1SJohn Crispin } 227171bb2f1SJohn Crispin 228171bb2f1SJohn Crispin static void ltq_shutdown_eiu_irq(struct irq_data *d) 229171bb2f1SJohn Crispin { 230171bb2f1SJohn Crispin int i; 231171bb2f1SJohn Crispin 232171bb2f1SJohn Crispin ltq_disable_irq(d); 233f97e5e8eSJohn Crispin for (i = 0; i < exin_avail; i++) { 234fe46e503SJohn Crispin if (d->hwirq == ltq_eiu_irq[i]) { 235171bb2f1SJohn Crispin /* disable */ 2363645da02SJohn Crispin ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), 237171bb2f1SJohn Crispin LTQ_EIU_EXIN_INEN); 238171bb2f1SJohn Crispin break; 239171bb2f1SJohn Crispin } 240171bb2f1SJohn Crispin } 241171bb2f1SJohn Crispin } 242171bb2f1SJohn Crispin 243*85cf2c37SPetr Cvek #if defined(CONFIG_SMP) 244*85cf2c37SPetr Cvek static int ltq_icu_irq_set_affinity(struct irq_data *d, 245*85cf2c37SPetr Cvek const struct cpumask *cpumask, bool force) 246*85cf2c37SPetr Cvek { 247*85cf2c37SPetr Cvek struct cpumask tmask; 248*85cf2c37SPetr Cvek 249*85cf2c37SPetr Cvek if (!cpumask_and(&tmask, cpumask, cpu_online_mask)) 250*85cf2c37SPetr Cvek return -EINVAL; 251*85cf2c37SPetr Cvek 252*85cf2c37SPetr Cvek irq_data_update_effective_affinity(d, &tmask); 253*85cf2c37SPetr Cvek 254*85cf2c37SPetr Cvek return IRQ_SET_MASK_OK; 255*85cf2c37SPetr Cvek } 256*85cf2c37SPetr Cvek #endif 257*85cf2c37SPetr Cvek 258171bb2f1SJohn Crispin static struct irq_chip ltq_irq_type = { 259891ab064SSudip Mukherjee .name = "icu", 260171bb2f1SJohn Crispin .irq_enable = ltq_enable_irq, 261171bb2f1SJohn Crispin .irq_disable = ltq_disable_irq, 262171bb2f1SJohn Crispin .irq_unmask = ltq_enable_irq, 263171bb2f1SJohn Crispin .irq_ack = ltq_ack_irq, 264171bb2f1SJohn Crispin .irq_mask = ltq_disable_irq, 265171bb2f1SJohn Crispin .irq_mask_ack = ltq_mask_and_ack_irq, 266*85cf2c37SPetr Cvek #if defined(CONFIG_SMP) 267*85cf2c37SPetr Cvek .irq_set_affinity = ltq_icu_irq_set_affinity, 268*85cf2c37SPetr Cvek #endif 269171bb2f1SJohn Crispin }; 270171bb2f1SJohn Crispin 271171bb2f1SJohn Crispin static struct irq_chip ltq_eiu_type = { 272891ab064SSudip Mukherjee .name = "eiu", 273171bb2f1SJohn Crispin .irq_startup = ltq_startup_eiu_irq, 274171bb2f1SJohn Crispin .irq_shutdown = ltq_shutdown_eiu_irq, 275171bb2f1SJohn Crispin .irq_enable = ltq_enable_irq, 276171bb2f1SJohn Crispin .irq_disable = ltq_disable_irq, 277171bb2f1SJohn Crispin .irq_unmask = ltq_enable_irq, 278171bb2f1SJohn Crispin .irq_ack = ltq_ack_irq, 279171bb2f1SJohn Crispin .irq_mask = ltq_disable_irq, 280171bb2f1SJohn Crispin .irq_mask_ack = ltq_mask_and_ack_irq, 28126365625SJohn Crispin .irq_set_type = ltq_eiu_settype, 282*85cf2c37SPetr Cvek #if defined(CONFIG_SMP) 283*85cf2c37SPetr Cvek .irq_set_affinity = ltq_icu_irq_set_affinity, 284*85cf2c37SPetr Cvek #endif 285171bb2f1SJohn Crispin }; 286171bb2f1SJohn Crispin 2872b4dba55SHauke Mehrtens static void ltq_hw_irq_handler(struct irq_desc *desc) 288171bb2f1SJohn Crispin { 28939588164SPetr Cvek unsigned int module = irq_desc_get_irq(desc) - 2; 290171bb2f1SJohn Crispin u32 irq; 29139588164SPetr Cvek irq_hw_number_t hwirq; 292*85cf2c37SPetr Cvek int vpe = smp_processor_id(); 293171bb2f1SJohn Crispin 294*85cf2c37SPetr Cvek irq = ltq_icu_r32(vpe, module, LTQ_ICU_IOSR); 295171bb2f1SJohn Crispin if (irq == 0) 296171bb2f1SJohn Crispin return; 297171bb2f1SJohn Crispin 2983645da02SJohn Crispin /* 2993645da02SJohn Crispin * silicon bug causes only the msb set to 1 to be valid. all 300171bb2f1SJohn Crispin * other bits might be bogus 301171bb2f1SJohn Crispin */ 302171bb2f1SJohn Crispin irq = __fls(irq); 3032b4dba55SHauke Mehrtens hwirq = irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module); 3042b4dba55SHauke Mehrtens generic_handle_irq(irq_linear_revmap(ltq_domain, hwirq)); 305171bb2f1SJohn Crispin 306171bb2f1SJohn Crispin /* if this is a EBU irq, we need to ack it or get a deadlock */ 3073645da02SJohn Crispin if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0) && LTQ_EBU_PCC_ISTAT) 308171bb2f1SJohn Crispin ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, 309171bb2f1SJohn Crispin LTQ_EBU_PCC_ISTAT); 310171bb2f1SJohn Crispin } 311171bb2f1SJohn Crispin 3123645da02SJohn Crispin static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 3133645da02SJohn Crispin { 3143645da02SJohn Crispin struct irq_chip *chip = <q_irq_type; 315*85cf2c37SPetr Cvek struct irq_data *data; 3163645da02SJohn Crispin int i; 3173645da02SJohn Crispin 3189c1628b6SJohn Crispin if (hw < MIPS_CPU_IRQ_CASCADE) 3199c1628b6SJohn Crispin return 0; 3209c1628b6SJohn Crispin 3213645da02SJohn Crispin for (i = 0; i < exin_avail; i++) 322fe46e503SJohn Crispin if (hw == ltq_eiu_irq[i]) 3233645da02SJohn Crispin chip = <q_eiu_type; 3243645da02SJohn Crispin 325*85cf2c37SPetr Cvek data = irq_get_irq_data(irq); 326*85cf2c37SPetr Cvek 327*85cf2c37SPetr Cvek irq_data_update_effective_affinity(data, cpumask_of(0)); 328*85cf2c37SPetr Cvek 3297bf0d5e8SHauke Mehrtens irq_set_chip_and_handler(irq, chip, handle_level_irq); 3303645da02SJohn Crispin 3313645da02SJohn Crispin return 0; 3323645da02SJohn Crispin } 3333645da02SJohn Crispin 3343645da02SJohn Crispin static const struct irq_domain_ops irq_domain_ops = { 3353645da02SJohn Crispin .xlate = irq_domain_xlate_onetwocell, 3363645da02SJohn Crispin .map = icu_map, 3373645da02SJohn Crispin }; 3383645da02SJohn Crispin 3393645da02SJohn Crispin int __init icu_of_init(struct device_node *node, struct device_node *parent) 340171bb2f1SJohn Crispin { 3413645da02SJohn Crispin struct device_node *eiu_node; 3423645da02SJohn Crispin struct resource res; 343*85cf2c37SPetr Cvek int i, ret, vpe; 344171bb2f1SJohn Crispin 345*85cf2c37SPetr Cvek /* load register regions of available ICUs */ 346*85cf2c37SPetr Cvek for_each_possible_cpu(vpe) { 347*85cf2c37SPetr Cvek if (of_address_to_resource(node, vpe, &res)) 348*85cf2c37SPetr Cvek panic("Failed to get icu%i memory range", vpe); 349171bb2f1SJohn Crispin 3506e807852SHauke Mehrtens if (!request_mem_region(res.start, resource_size(&res), 3516e807852SHauke Mehrtens res.name)) 352*85cf2c37SPetr Cvek pr_err("Failed to request icu%i memory\n", vpe); 353171bb2f1SJohn Crispin 354*85cf2c37SPetr Cvek ltq_icu_membase[vpe] = ioremap_nocache(res.start, 35561fa969fSJohn Crispin resource_size(&res)); 356*85cf2c37SPetr Cvek 357*85cf2c37SPetr Cvek if (!ltq_icu_membase[vpe]) 358*85cf2c37SPetr Cvek panic("Failed to remap icu%i memory", vpe); 35961fa969fSJohn Crispin } 360171bb2f1SJohn Crispin 36116f70b56SJohn Crispin /* turn off all irqs by default */ 362*85cf2c37SPetr Cvek for_each_possible_cpu(vpe) { 36361fa969fSJohn Crispin for (i = 0; i < MAX_IM; i++) { 364171bb2f1SJohn Crispin /* make sure all irqs are turned off by default */ 365*85cf2c37SPetr Cvek ltq_icu_w32(vpe, i, 0, LTQ_ICU_IER); 366*85cf2c37SPetr Cvek 367171bb2f1SJohn Crispin /* clear all possibly pending interrupts */ 368*85cf2c37SPetr Cvek ltq_icu_w32(vpe, i, ~0, LTQ_ICU_ISR); 369*85cf2c37SPetr Cvek ltq_icu_w32(vpe, i, ~0, LTQ_ICU_IMR); 370*85cf2c37SPetr Cvek 371*85cf2c37SPetr Cvek /* clear resend */ 372*85cf2c37SPetr Cvek ltq_icu_w32(vpe, i, 0, LTQ_ICU_IRSR); 373*85cf2c37SPetr Cvek } 37416f70b56SJohn Crispin } 375171bb2f1SJohn Crispin 376171bb2f1SJohn Crispin mips_cpu_irq_init(); 377171bb2f1SJohn Crispin 37861fa969fSJohn Crispin for (i = 0; i < MAX_IM; i++) 3796c356edaSFelix Fietkau irq_set_chained_handler(i + 2, ltq_hw_irq_handler); 380171bb2f1SJohn Crispin 381c2c9c788SJohn Crispin ltq_domain = irq_domain_add_linear(node, 38261fa969fSJohn Crispin (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE, 3833645da02SJohn Crispin &irq_domain_ops, 0); 384171bb2f1SJohn Crispin 38559c11579SJohn Crispin /* tell oprofile which irq to use */ 386a669efc4SAndrew Bresticker ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); 387c2c9c788SJohn Crispin 388d32caf94SJohn Crispin /* the external interrupts are optional and xway only */ 389d32caf94SJohn Crispin eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); 390d32caf94SJohn Crispin if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { 391d32caf94SJohn Crispin /* find out how many external irq sources we have */ 392fe46e503SJohn Crispin exin_avail = of_property_count_u32_elems(eiu_node, 393fe46e503SJohn Crispin "lantiq,eiu-irqs"); 394d32caf94SJohn Crispin 395d32caf94SJohn Crispin if (exin_avail > MAX_EIU) 396d32caf94SJohn Crispin exin_avail = MAX_EIU; 397d32caf94SJohn Crispin 398fe46e503SJohn Crispin ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs", 399d32caf94SJohn Crispin ltq_eiu_irq, exin_avail); 400fe46e503SJohn Crispin if (ret) 401d32caf94SJohn Crispin panic("failed to load external irq resources"); 402d32caf94SJohn Crispin 4036e807852SHauke Mehrtens if (!request_mem_region(res.start, resource_size(&res), 4046e807852SHauke Mehrtens res.name)) 405d32caf94SJohn Crispin pr_err("Failed to request eiu memory"); 406d32caf94SJohn Crispin 407d32caf94SJohn Crispin ltq_eiu_membase = ioremap_nocache(res.start, 408d32caf94SJohn Crispin resource_size(&res)); 409d32caf94SJohn Crispin if (!ltq_eiu_membase) 410d32caf94SJohn Crispin panic("Failed to remap eiu memory"); 411d32caf94SJohn Crispin } 412d32caf94SJohn Crispin 4133645da02SJohn Crispin return 0; 414171bb2f1SJohn Crispin } 415171bb2f1SJohn Crispin 416a669efc4SAndrew Bresticker int get_c0_perfcount_int(void) 417a669efc4SAndrew Bresticker { 418a669efc4SAndrew Bresticker return ltq_perfcount_irq; 419a669efc4SAndrew Bresticker } 4200cb0985fSFelix Fietkau EXPORT_SYMBOL_GPL(get_c0_perfcount_int); 421a669efc4SAndrew Bresticker 422078a55fcSPaul Gortmaker unsigned int get_c0_compare_int(void) 423171bb2f1SJohn Crispin { 424390d1b46SHauke Mehrtens return CP0_LEGACY_COMPARE_IRQ; 425171bb2f1SJohn Crispin } 4263645da02SJohn Crispin 42764a95283SPetr Cvek static const struct of_device_id of_irq_ids[] __initconst = { 4283645da02SJohn Crispin { .compatible = "lantiq,icu", .data = icu_of_init }, 4293645da02SJohn Crispin {}, 4303645da02SJohn Crispin }; 4313645da02SJohn Crispin 4323645da02SJohn Crispin void __init arch_init_irq(void) 4333645da02SJohn Crispin { 4343645da02SJohn Crispin of_irq_init(of_irq_ids); 4353645da02SJohn Crispin } 436