162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2010 John Crispin <john@phrozen.org> 562306a36Sopenharmony_ci * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/ioport.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/irqchip.h> 1262306a36Sopenharmony_ci#include <linux/irqdomain.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_address.h> 1562306a36Sopenharmony_ci#include <linux/of_irq.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/bootinfo.h> 1862306a36Sopenharmony_ci#include <asm/irq_cpu.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <lantiq_soc.h> 2162306a36Sopenharmony_ci#include <irq.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* register definitions - internal irqs */ 2462306a36Sopenharmony_ci#define LTQ_ICU_ISR 0x0000 2562306a36Sopenharmony_ci#define LTQ_ICU_IER 0x0008 2662306a36Sopenharmony_ci#define LTQ_ICU_IOSR 0x0010 2762306a36Sopenharmony_ci#define LTQ_ICU_IRSR 0x0018 2862306a36Sopenharmony_ci#define LTQ_ICU_IMR 0x0020 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define LTQ_ICU_IM_SIZE 0x28 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* register definitions - external irqs */ 3362306a36Sopenharmony_ci#define LTQ_EIU_EXIN_C 0x0000 3462306a36Sopenharmony_ci#define LTQ_EIU_EXIN_INIC 0x0004 3562306a36Sopenharmony_ci#define LTQ_EIU_EXIN_INC 0x0008 3662306a36Sopenharmony_ci#define LTQ_EIU_EXIN_INEN 0x000C 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* number of external interrupts */ 3962306a36Sopenharmony_ci#define MAX_EIU 6 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* the performance counter */ 4262306a36Sopenharmony_ci#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * irqs generated by devices attached to the EBU need to be acked in 4662306a36Sopenharmony_ci * a special manner 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define LTQ_ICU_EBU_IRQ 22 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define ltq_icu_w32(vpe, m, x, y) \ 5162306a36Sopenharmony_ci ltq_w32((x), ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (y)) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define ltq_icu_r32(vpe, m, x) \ 5462306a36Sopenharmony_ci ltq_r32(ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (x)) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) 5762306a36Sopenharmony_ci#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* we have a cascade of 8 irqs */ 6062306a36Sopenharmony_ci#define MIPS_CPU_IRQ_CASCADE 8 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int exin_avail; 6362306a36Sopenharmony_cistatic u32 ltq_eiu_irq[MAX_EIU]; 6462306a36Sopenharmony_cistatic void __iomem *ltq_icu_membase[NR_CPUS]; 6562306a36Sopenharmony_cistatic void __iomem *ltq_eiu_membase; 6662306a36Sopenharmony_cistatic struct irq_domain *ltq_domain; 6762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ltq_eiu_lock); 6862306a36Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(ltq_icu_lock); 6962306a36Sopenharmony_cistatic int ltq_perfcount_irq; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciint ltq_eiu_get_irq(int exin) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (exin < exin_avail) 7462306a36Sopenharmony_ci return ltq_eiu_irq[exin]; 7562306a36Sopenharmony_ci return -1; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid ltq_disable_irq(struct irq_data *d) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 8162306a36Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 8262306a36Sopenharmony_ci unsigned long flags; 8362306a36Sopenharmony_ci int vpe; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 8862306a36Sopenharmony_ci for_each_present_cpu(vpe) { 8962306a36Sopenharmony_ci ltq_icu_w32(vpe, im, 9062306a36Sopenharmony_ci ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 9162306a36Sopenharmony_ci LTQ_ICU_IER); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_civoid ltq_mask_and_ack_irq(struct irq_data *d) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 9962306a36Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 10062306a36Sopenharmony_ci unsigned long flags; 10162306a36Sopenharmony_ci int vpe; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 10662306a36Sopenharmony_ci for_each_present_cpu(vpe) { 10762306a36Sopenharmony_ci ltq_icu_w32(vpe, im, 10862306a36Sopenharmony_ci ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 10962306a36Sopenharmony_ci LTQ_ICU_IER); 11062306a36Sopenharmony_ci ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void ltq_ack_irq(struct irq_data *d) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 11862306a36Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 11962306a36Sopenharmony_ci unsigned long flags; 12062306a36Sopenharmony_ci int vpe; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 12562306a36Sopenharmony_ci for_each_present_cpu(vpe) { 12662306a36Sopenharmony_ci ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_civoid ltq_enable_irq(struct irq_data *d) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 13462306a36Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 13562306a36Sopenharmony_ci unsigned long flags; 13662306a36Sopenharmony_ci int vpe; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci vpe = cpumask_first(irq_data_get_effective_affinity_mask(d)); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* This shouldn't be even possible, maybe during CPU hotplug spam */ 14362306a36Sopenharmony_ci if (unlikely(vpe >= nr_cpu_ids)) 14462306a36Sopenharmony_ci vpe = smp_processor_id(); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci ltq_icu_w32(vpe, im, ltq_icu_r32(vpe, im, LTQ_ICU_IER) | BIT(offset), 14962306a36Sopenharmony_ci LTQ_ICU_IER); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int ltq_eiu_settype(struct irq_data *d, unsigned int type) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci int i; 15762306a36Sopenharmony_ci unsigned long flags; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 16062306a36Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 16162306a36Sopenharmony_ci int val = 0; 16262306a36Sopenharmony_ci int edge = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci switch (type) { 16562306a36Sopenharmony_ci case IRQF_TRIGGER_NONE: 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci case IRQF_TRIGGER_RISING: 16862306a36Sopenharmony_ci val = 1; 16962306a36Sopenharmony_ci edge = 1; 17062306a36Sopenharmony_ci break; 17162306a36Sopenharmony_ci case IRQF_TRIGGER_FALLING: 17262306a36Sopenharmony_ci val = 2; 17362306a36Sopenharmony_ci edge = 1; 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: 17662306a36Sopenharmony_ci val = 3; 17762306a36Sopenharmony_ci edge = 1; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci case IRQF_TRIGGER_HIGH: 18062306a36Sopenharmony_ci val = 5; 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case IRQF_TRIGGER_LOW: 18362306a36Sopenharmony_ci val = 6; 18462306a36Sopenharmony_ci break; 18562306a36Sopenharmony_ci default: 18662306a36Sopenharmony_ci pr_err("invalid type %d for irq %ld\n", 18762306a36Sopenharmony_ci type, d->hwirq); 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci if (edge) 19262306a36Sopenharmony_ci irq_set_handler(d->hwirq, handle_edge_irq); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci spin_lock_irqsave(<q_eiu_lock, flags); 19562306a36Sopenharmony_ci ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) & 19662306a36Sopenharmony_ci (~(7 << (i * 4)))) | (val << (i * 4)), 19762306a36Sopenharmony_ci LTQ_EIU_EXIN_C); 19862306a36Sopenharmony_ci spin_unlock_irqrestore(<q_eiu_lock, flags); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic unsigned int ltq_startup_eiu_irq(struct irq_data *d) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci int i; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci ltq_enable_irq(d); 21062306a36Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 21162306a36Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 21262306a36Sopenharmony_ci /* by default we are low level triggered */ 21362306a36Sopenharmony_ci ltq_eiu_settype(d, IRQF_TRIGGER_LOW); 21462306a36Sopenharmony_ci /* clear all pending */ 21562306a36Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i), 21662306a36Sopenharmony_ci LTQ_EIU_EXIN_INC); 21762306a36Sopenharmony_ci /* enable */ 21862306a36Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), 21962306a36Sopenharmony_ci LTQ_EIU_EXIN_INEN); 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void ltq_shutdown_eiu_irq(struct irq_data *d) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci int i; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci ltq_disable_irq(d); 23262306a36Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 23362306a36Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 23462306a36Sopenharmony_ci /* disable */ 23562306a36Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), 23662306a36Sopenharmony_ci LTQ_EIU_EXIN_INEN); 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci#if defined(CONFIG_SMP) 24362306a36Sopenharmony_cistatic int ltq_icu_irq_set_affinity(struct irq_data *d, 24462306a36Sopenharmony_ci const struct cpumask *cpumask, bool force) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct cpumask tmask; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (!cpumask_and(&tmask, cpumask, cpu_online_mask)) 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci irq_data_update_effective_affinity(d, &tmask); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return IRQ_SET_MASK_OK; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci#endif 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct irq_chip ltq_irq_type = { 25862306a36Sopenharmony_ci .name = "icu", 25962306a36Sopenharmony_ci .irq_enable = ltq_enable_irq, 26062306a36Sopenharmony_ci .irq_disable = ltq_disable_irq, 26162306a36Sopenharmony_ci .irq_unmask = ltq_enable_irq, 26262306a36Sopenharmony_ci .irq_ack = ltq_ack_irq, 26362306a36Sopenharmony_ci .irq_mask = ltq_disable_irq, 26462306a36Sopenharmony_ci .irq_mask_ack = ltq_mask_and_ack_irq, 26562306a36Sopenharmony_ci#if defined(CONFIG_SMP) 26662306a36Sopenharmony_ci .irq_set_affinity = ltq_icu_irq_set_affinity, 26762306a36Sopenharmony_ci#endif 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic struct irq_chip ltq_eiu_type = { 27162306a36Sopenharmony_ci .name = "eiu", 27262306a36Sopenharmony_ci .irq_startup = ltq_startup_eiu_irq, 27362306a36Sopenharmony_ci .irq_shutdown = ltq_shutdown_eiu_irq, 27462306a36Sopenharmony_ci .irq_enable = ltq_enable_irq, 27562306a36Sopenharmony_ci .irq_disable = ltq_disable_irq, 27662306a36Sopenharmony_ci .irq_unmask = ltq_enable_irq, 27762306a36Sopenharmony_ci .irq_ack = ltq_ack_irq, 27862306a36Sopenharmony_ci .irq_mask = ltq_disable_irq, 27962306a36Sopenharmony_ci .irq_mask_ack = ltq_mask_and_ack_irq, 28062306a36Sopenharmony_ci .irq_set_type = ltq_eiu_settype, 28162306a36Sopenharmony_ci#if defined(CONFIG_SMP) 28262306a36Sopenharmony_ci .irq_set_affinity = ltq_icu_irq_set_affinity, 28362306a36Sopenharmony_ci#endif 28462306a36Sopenharmony_ci}; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void ltq_hw_irq_handler(struct irq_desc *desc) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci unsigned int module = irq_desc_get_irq(desc) - 2; 28962306a36Sopenharmony_ci u32 irq; 29062306a36Sopenharmony_ci irq_hw_number_t hwirq; 29162306a36Sopenharmony_ci int vpe = smp_processor_id(); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci irq = ltq_icu_r32(vpe, module, LTQ_ICU_IOSR); 29462306a36Sopenharmony_ci if (irq == 0) 29562306a36Sopenharmony_ci return; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * silicon bug causes only the msb set to 1 to be valid. all 29962306a36Sopenharmony_ci * other bits might be bogus 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci irq = __fls(irq); 30262306a36Sopenharmony_ci hwirq = irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module); 30362306a36Sopenharmony_ci generic_handle_domain_irq(ltq_domain, hwirq); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* if this is a EBU irq, we need to ack it or get a deadlock */ 30662306a36Sopenharmony_ci if (irq == LTQ_ICU_EBU_IRQ && !module && LTQ_EBU_PCC_ISTAT != 0) 30762306a36Sopenharmony_ci ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, 30862306a36Sopenharmony_ci LTQ_EBU_PCC_ISTAT); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct irq_chip *chip = <q_irq_type; 31462306a36Sopenharmony_ci struct irq_data *data; 31562306a36Sopenharmony_ci int i; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (hw < MIPS_CPU_IRQ_CASCADE) 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci for (i = 0; i < exin_avail; i++) 32162306a36Sopenharmony_ci if (hw == ltq_eiu_irq[i]) 32262306a36Sopenharmony_ci chip = <q_eiu_type; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci data = irq_get_irq_data(irq); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci irq_data_update_effective_affinity(data, cpumask_of(0)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci irq_set_chip_and_handler(irq, chip, handle_level_irq); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic const struct irq_domain_ops irq_domain_ops = { 33462306a36Sopenharmony_ci .xlate = irq_domain_xlate_onetwocell, 33562306a36Sopenharmony_ci .map = icu_map, 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ciint __init icu_of_init(struct device_node *node, struct device_node *parent) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci struct device_node *eiu_node; 34162306a36Sopenharmony_ci struct resource res; 34262306a36Sopenharmony_ci int i, ret, vpe; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* load register regions of available ICUs */ 34562306a36Sopenharmony_ci for_each_possible_cpu(vpe) { 34662306a36Sopenharmony_ci if (of_address_to_resource(node, vpe, &res)) 34762306a36Sopenharmony_ci panic("Failed to get icu%i memory range", vpe); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), 35062306a36Sopenharmony_ci res.name)) 35162306a36Sopenharmony_ci pr_err("Failed to request icu%i memory\n", vpe); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ltq_icu_membase[vpe] = ioremap(res.start, 35462306a36Sopenharmony_ci resource_size(&res)); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!ltq_icu_membase[vpe]) 35762306a36Sopenharmony_ci panic("Failed to remap icu%i memory", vpe); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* turn off all irqs by default */ 36162306a36Sopenharmony_ci for_each_possible_cpu(vpe) { 36262306a36Sopenharmony_ci for (i = 0; i < MAX_IM; i++) { 36362306a36Sopenharmony_ci /* make sure all irqs are turned off by default */ 36462306a36Sopenharmony_ci ltq_icu_w32(vpe, i, 0, LTQ_ICU_IER); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* clear all possibly pending interrupts */ 36762306a36Sopenharmony_ci ltq_icu_w32(vpe, i, ~0, LTQ_ICU_ISR); 36862306a36Sopenharmony_ci ltq_icu_w32(vpe, i, ~0, LTQ_ICU_IMR); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* clear resend */ 37162306a36Sopenharmony_ci ltq_icu_w32(vpe, i, 0, LTQ_ICU_IRSR); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci mips_cpu_irq_init(); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci for (i = 0; i < MAX_IM; i++) 37862306a36Sopenharmony_ci irq_set_chained_handler(i + 2, ltq_hw_irq_handler); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci ltq_domain = irq_domain_add_linear(node, 38162306a36Sopenharmony_ci (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE, 38262306a36Sopenharmony_ci &irq_domain_ops, 0); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* tell oprofile which irq to use */ 38562306a36Sopenharmony_ci ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* the external interrupts are optional and xway only */ 38862306a36Sopenharmony_ci eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); 38962306a36Sopenharmony_ci if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { 39062306a36Sopenharmony_ci /* find out how many external irq sources we have */ 39162306a36Sopenharmony_ci exin_avail = of_property_count_u32_elems(eiu_node, 39262306a36Sopenharmony_ci "lantiq,eiu-irqs"); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (exin_avail > MAX_EIU) 39562306a36Sopenharmony_ci exin_avail = MAX_EIU; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs", 39862306a36Sopenharmony_ci ltq_eiu_irq, exin_avail); 39962306a36Sopenharmony_ci if (ret) 40062306a36Sopenharmony_ci panic("failed to load external irq resources"); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), 40362306a36Sopenharmony_ci res.name)) 40462306a36Sopenharmony_ci pr_err("Failed to request eiu memory"); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ltq_eiu_membase = ioremap(res.start, 40762306a36Sopenharmony_ci resource_size(&res)); 40862306a36Sopenharmony_ci if (!ltq_eiu_membase) 40962306a36Sopenharmony_ci panic("Failed to remap eiu memory"); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci of_node_put(eiu_node); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ciint get_c0_perfcount_int(void) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return ltq_perfcount_irq; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(get_c0_perfcount_int); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ciunsigned int get_c0_compare_int(void) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci return CP0_LEGACY_COMPARE_IRQ; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ciIRQCHIP_DECLARE(lantiq_icu, "lantiq,icu", icu_of_init); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_civoid __init arch_init_irq(void) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci irqchip_init(); 43262306a36Sopenharmony_ci} 433