18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2010 John Crispin <john@phrozen.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/ioport.h> 108c2ecf20Sopenharmony_ci#include <linux/sched.h> 118c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 128c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 178c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <lantiq_soc.h> 208c2ecf20Sopenharmony_ci#include <irq.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* register definitions - internal irqs */ 238c2ecf20Sopenharmony_ci#define LTQ_ICU_ISR 0x0000 248c2ecf20Sopenharmony_ci#define LTQ_ICU_IER 0x0008 258c2ecf20Sopenharmony_ci#define LTQ_ICU_IOSR 0x0010 268c2ecf20Sopenharmony_ci#define LTQ_ICU_IRSR 0x0018 278c2ecf20Sopenharmony_ci#define LTQ_ICU_IMR 0x0020 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define LTQ_ICU_IM_SIZE 0x28 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* register definitions - external irqs */ 328c2ecf20Sopenharmony_ci#define LTQ_EIU_EXIN_C 0x0000 338c2ecf20Sopenharmony_ci#define LTQ_EIU_EXIN_INIC 0x0004 348c2ecf20Sopenharmony_ci#define LTQ_EIU_EXIN_INC 0x0008 358c2ecf20Sopenharmony_ci#define LTQ_EIU_EXIN_INEN 0x000C 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* number of external interrupts */ 388c2ecf20Sopenharmony_ci#define MAX_EIU 6 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* the performance counter */ 418c2ecf20Sopenharmony_ci#define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * irqs generated by devices attached to the EBU need to be acked in 458c2ecf20Sopenharmony_ci * a special manner 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define LTQ_ICU_EBU_IRQ 22 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define ltq_icu_w32(vpe, m, x, y) \ 508c2ecf20Sopenharmony_ci ltq_w32((x), ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (y)) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define ltq_icu_r32(vpe, m, x) \ 538c2ecf20Sopenharmony_ci ltq_r32(ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (x)) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) 568c2ecf20Sopenharmony_ci#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* we have a cascade of 8 irqs */ 598c2ecf20Sopenharmony_ci#define MIPS_CPU_IRQ_CASCADE 8 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int exin_avail; 628c2ecf20Sopenharmony_cistatic u32 ltq_eiu_irq[MAX_EIU]; 638c2ecf20Sopenharmony_cistatic void __iomem *ltq_icu_membase[NR_CPUS]; 648c2ecf20Sopenharmony_cistatic void __iomem *ltq_eiu_membase; 658c2ecf20Sopenharmony_cistatic struct irq_domain *ltq_domain; 668c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ltq_eiu_lock); 678c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(ltq_icu_lock); 688c2ecf20Sopenharmony_cistatic int ltq_perfcount_irq; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciint ltq_eiu_get_irq(int exin) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (exin < exin_avail) 738c2ecf20Sopenharmony_ci return ltq_eiu_irq[exin]; 748c2ecf20Sopenharmony_ci return -1; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_civoid ltq_disable_irq(struct irq_data *d) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 808c2ecf20Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 818c2ecf20Sopenharmony_ci unsigned long flags; 828c2ecf20Sopenharmony_ci int vpe; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 878c2ecf20Sopenharmony_ci for_each_present_cpu(vpe) { 888c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, im, 898c2ecf20Sopenharmony_ci ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 908c2ecf20Sopenharmony_ci LTQ_ICU_IER); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_civoid ltq_mask_and_ack_irq(struct irq_data *d) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 988c2ecf20Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 998c2ecf20Sopenharmony_ci unsigned long flags; 1008c2ecf20Sopenharmony_ci int vpe; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 1058c2ecf20Sopenharmony_ci for_each_present_cpu(vpe) { 1068c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, im, 1078c2ecf20Sopenharmony_ci ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), 1088c2ecf20Sopenharmony_ci LTQ_ICU_IER); 1098c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void ltq_ack_irq(struct irq_data *d) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 1178c2ecf20Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 1188c2ecf20Sopenharmony_ci unsigned long flags; 1198c2ecf20Sopenharmony_ci int vpe; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 1248c2ecf20Sopenharmony_ci for_each_present_cpu(vpe) { 1258c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_civoid ltq_enable_irq(struct irq_data *d) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; 1338c2ecf20Sopenharmony_ci unsigned long im = offset / INT_NUM_IM_OFFSET; 1348c2ecf20Sopenharmony_ci unsigned long flags; 1358c2ecf20Sopenharmony_ci int vpe; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci offset %= INT_NUM_IM_OFFSET; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci vpe = cpumask_first(irq_data_get_effective_affinity_mask(d)); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* This shouldn't be even possible, maybe during CPU hotplug spam */ 1428c2ecf20Sopenharmony_ci if (unlikely(vpe >= nr_cpu_ids)) 1438c2ecf20Sopenharmony_ci vpe = smp_processor_id(); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(<q_icu_lock, flags); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, im, ltq_icu_r32(vpe, im, LTQ_ICU_IER) | BIT(offset), 1488c2ecf20Sopenharmony_ci LTQ_ICU_IER); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(<q_icu_lock, flags); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int ltq_eiu_settype(struct irq_data *d, unsigned int type) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci int i; 1568c2ecf20Sopenharmony_ci unsigned long flags; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 1598c2ecf20Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 1608c2ecf20Sopenharmony_ci int val = 0; 1618c2ecf20Sopenharmony_ci int edge = 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci switch (type) { 1648c2ecf20Sopenharmony_ci case IRQF_TRIGGER_NONE: 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci case IRQF_TRIGGER_RISING: 1678c2ecf20Sopenharmony_ci val = 1; 1688c2ecf20Sopenharmony_ci edge = 1; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case IRQF_TRIGGER_FALLING: 1718c2ecf20Sopenharmony_ci val = 2; 1728c2ecf20Sopenharmony_ci edge = 1; 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: 1758c2ecf20Sopenharmony_ci val = 3; 1768c2ecf20Sopenharmony_ci edge = 1; 1778c2ecf20Sopenharmony_ci break; 1788c2ecf20Sopenharmony_ci case IRQF_TRIGGER_HIGH: 1798c2ecf20Sopenharmony_ci val = 5; 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case IRQF_TRIGGER_LOW: 1828c2ecf20Sopenharmony_ci val = 6; 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci default: 1858c2ecf20Sopenharmony_ci pr_err("invalid type %d for irq %ld\n", 1868c2ecf20Sopenharmony_ci type, d->hwirq); 1878c2ecf20Sopenharmony_ci return -EINVAL; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (edge) 1918c2ecf20Sopenharmony_ci irq_set_handler(d->hwirq, handle_edge_irq); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci spin_lock_irqsave(<q_eiu_lock, flags); 1948c2ecf20Sopenharmony_ci ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) & 1958c2ecf20Sopenharmony_ci (~(7 << (i * 4)))) | (val << (i * 4)), 1968c2ecf20Sopenharmony_ci LTQ_EIU_EXIN_C); 1978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(<q_eiu_lock, flags); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic unsigned int ltq_startup_eiu_irq(struct irq_data *d) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci int i; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ltq_enable_irq(d); 2098c2ecf20Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 2108c2ecf20Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 2118c2ecf20Sopenharmony_ci /* by default we are low level triggered */ 2128c2ecf20Sopenharmony_ci ltq_eiu_settype(d, IRQF_TRIGGER_LOW); 2138c2ecf20Sopenharmony_ci /* clear all pending */ 2148c2ecf20Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i), 2158c2ecf20Sopenharmony_ci LTQ_EIU_EXIN_INC); 2168c2ecf20Sopenharmony_ci /* enable */ 2178c2ecf20Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), 2188c2ecf20Sopenharmony_ci LTQ_EIU_EXIN_INEN); 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void ltq_shutdown_eiu_irq(struct irq_data *d) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int i; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci ltq_disable_irq(d); 2318c2ecf20Sopenharmony_ci for (i = 0; i < exin_avail; i++) { 2328c2ecf20Sopenharmony_ci if (d->hwirq == ltq_eiu_irq[i]) { 2338c2ecf20Sopenharmony_ci /* disable */ 2348c2ecf20Sopenharmony_ci ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), 2358c2ecf20Sopenharmony_ci LTQ_EIU_EXIN_INEN); 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP) 2428c2ecf20Sopenharmony_cistatic int ltq_icu_irq_set_affinity(struct irq_data *d, 2438c2ecf20Sopenharmony_ci const struct cpumask *cpumask, bool force) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct cpumask tmask; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!cpumask_and(&tmask, cpumask, cpu_online_mask)) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci irq_data_update_effective_affinity(d, &tmask); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return IRQ_SET_MASK_OK; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci#endif 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic struct irq_chip ltq_irq_type = { 2578c2ecf20Sopenharmony_ci .name = "icu", 2588c2ecf20Sopenharmony_ci .irq_enable = ltq_enable_irq, 2598c2ecf20Sopenharmony_ci .irq_disable = ltq_disable_irq, 2608c2ecf20Sopenharmony_ci .irq_unmask = ltq_enable_irq, 2618c2ecf20Sopenharmony_ci .irq_ack = ltq_ack_irq, 2628c2ecf20Sopenharmony_ci .irq_mask = ltq_disable_irq, 2638c2ecf20Sopenharmony_ci .irq_mask_ack = ltq_mask_and_ack_irq, 2648c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP) 2658c2ecf20Sopenharmony_ci .irq_set_affinity = ltq_icu_irq_set_affinity, 2668c2ecf20Sopenharmony_ci#endif 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic struct irq_chip ltq_eiu_type = { 2708c2ecf20Sopenharmony_ci .name = "eiu", 2718c2ecf20Sopenharmony_ci .irq_startup = ltq_startup_eiu_irq, 2728c2ecf20Sopenharmony_ci .irq_shutdown = ltq_shutdown_eiu_irq, 2738c2ecf20Sopenharmony_ci .irq_enable = ltq_enable_irq, 2748c2ecf20Sopenharmony_ci .irq_disable = ltq_disable_irq, 2758c2ecf20Sopenharmony_ci .irq_unmask = ltq_enable_irq, 2768c2ecf20Sopenharmony_ci .irq_ack = ltq_ack_irq, 2778c2ecf20Sopenharmony_ci .irq_mask = ltq_disable_irq, 2788c2ecf20Sopenharmony_ci .irq_mask_ack = ltq_mask_and_ack_irq, 2798c2ecf20Sopenharmony_ci .irq_set_type = ltq_eiu_settype, 2808c2ecf20Sopenharmony_ci#if defined(CONFIG_SMP) 2818c2ecf20Sopenharmony_ci .irq_set_affinity = ltq_icu_irq_set_affinity, 2828c2ecf20Sopenharmony_ci#endif 2838c2ecf20Sopenharmony_ci}; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic void ltq_hw_irq_handler(struct irq_desc *desc) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci unsigned int module = irq_desc_get_irq(desc) - 2; 2888c2ecf20Sopenharmony_ci u32 irq; 2898c2ecf20Sopenharmony_ci irq_hw_number_t hwirq; 2908c2ecf20Sopenharmony_ci int vpe = smp_processor_id(); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci irq = ltq_icu_r32(vpe, module, LTQ_ICU_IOSR); 2938c2ecf20Sopenharmony_ci if (irq == 0) 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci /* 2978c2ecf20Sopenharmony_ci * silicon bug causes only the msb set to 1 to be valid. all 2988c2ecf20Sopenharmony_ci * other bits might be bogus 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci irq = __fls(irq); 3018c2ecf20Sopenharmony_ci hwirq = irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module); 3028c2ecf20Sopenharmony_ci generic_handle_irq(irq_linear_revmap(ltq_domain, hwirq)); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* if this is a EBU irq, we need to ack it or get a deadlock */ 3058c2ecf20Sopenharmony_ci if (irq == LTQ_ICU_EBU_IRQ && !module && LTQ_EBU_PCC_ISTAT != 0) 3068c2ecf20Sopenharmony_ci ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, 3078c2ecf20Sopenharmony_ci LTQ_EBU_PCC_ISTAT); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct irq_chip *chip = <q_irq_type; 3138c2ecf20Sopenharmony_ci struct irq_data *data; 3148c2ecf20Sopenharmony_ci int i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (hw < MIPS_CPU_IRQ_CASCADE) 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci for (i = 0; i < exin_avail; i++) 3208c2ecf20Sopenharmony_ci if (hw == ltq_eiu_irq[i]) 3218c2ecf20Sopenharmony_ci chip = <q_eiu_type; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci data = irq_get_irq_data(irq); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci irq_data_update_effective_affinity(data, cpumask_of(0)); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, chip, handle_level_irq); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return 0; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic const struct irq_domain_ops irq_domain_ops = { 3338c2ecf20Sopenharmony_ci .xlate = irq_domain_xlate_onetwocell, 3348c2ecf20Sopenharmony_ci .map = icu_map, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ciint __init icu_of_init(struct device_node *node, struct device_node *parent) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct device_node *eiu_node; 3408c2ecf20Sopenharmony_ci struct resource res; 3418c2ecf20Sopenharmony_ci int i, ret, vpe; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* load register regions of available ICUs */ 3448c2ecf20Sopenharmony_ci for_each_possible_cpu(vpe) { 3458c2ecf20Sopenharmony_ci if (of_address_to_resource(node, vpe, &res)) 3468c2ecf20Sopenharmony_ci panic("Failed to get icu%i memory range", vpe); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), 3498c2ecf20Sopenharmony_ci res.name)) 3508c2ecf20Sopenharmony_ci pr_err("Failed to request icu%i memory\n", vpe); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci ltq_icu_membase[vpe] = ioremap(res.start, 3538c2ecf20Sopenharmony_ci resource_size(&res)); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (!ltq_icu_membase[vpe]) 3568c2ecf20Sopenharmony_ci panic("Failed to remap icu%i memory", vpe); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* turn off all irqs by default */ 3608c2ecf20Sopenharmony_ci for_each_possible_cpu(vpe) { 3618c2ecf20Sopenharmony_ci for (i = 0; i < MAX_IM; i++) { 3628c2ecf20Sopenharmony_ci /* make sure all irqs are turned off by default */ 3638c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, i, 0, LTQ_ICU_IER); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* clear all possibly pending interrupts */ 3668c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, i, ~0, LTQ_ICU_ISR); 3678c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, i, ~0, LTQ_ICU_IMR); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* clear resend */ 3708c2ecf20Sopenharmony_ci ltq_icu_w32(vpe, i, 0, LTQ_ICU_IRSR); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci mips_cpu_irq_init(); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (i = 0; i < MAX_IM; i++) 3778c2ecf20Sopenharmony_ci irq_set_chained_handler(i + 2, ltq_hw_irq_handler); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ltq_domain = irq_domain_add_linear(node, 3808c2ecf20Sopenharmony_ci (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE, 3818c2ecf20Sopenharmony_ci &irq_domain_ops, 0); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* tell oprofile which irq to use */ 3848c2ecf20Sopenharmony_ci ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* the external interrupts are optional and xway only */ 3878c2ecf20Sopenharmony_ci eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); 3888c2ecf20Sopenharmony_ci if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { 3898c2ecf20Sopenharmony_ci /* find out how many external irq sources we have */ 3908c2ecf20Sopenharmony_ci exin_avail = of_property_count_u32_elems(eiu_node, 3918c2ecf20Sopenharmony_ci "lantiq,eiu-irqs"); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (exin_avail > MAX_EIU) 3948c2ecf20Sopenharmony_ci exin_avail = MAX_EIU; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs", 3978c2ecf20Sopenharmony_ci ltq_eiu_irq, exin_avail); 3988c2ecf20Sopenharmony_ci if (ret) 3998c2ecf20Sopenharmony_ci panic("failed to load external irq resources"); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci if (!request_mem_region(res.start, resource_size(&res), 4028c2ecf20Sopenharmony_ci res.name)) 4038c2ecf20Sopenharmony_ci pr_err("Failed to request eiu memory"); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ltq_eiu_membase = ioremap(res.start, 4068c2ecf20Sopenharmony_ci resource_size(&res)); 4078c2ecf20Sopenharmony_ci if (!ltq_eiu_membase) 4088c2ecf20Sopenharmony_ci panic("Failed to remap eiu memory"); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ciint get_c0_perfcount_int(void) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci return ltq_perfcount_irq; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_c0_perfcount_int); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciunsigned int get_c0_compare_int(void) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci return CP0_LEGACY_COMPARE_IRQ; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic const struct of_device_id of_irq_ids[] __initconst = { 4268c2ecf20Sopenharmony_ci { .compatible = "lantiq,icu", .data = icu_of_init }, 4278c2ecf20Sopenharmony_ci {}, 4288c2ecf20Sopenharmony_ci}; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_civoid __init arch_init_irq(void) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci of_irq_init(of_irq_ids); 4338c2ecf20Sopenharmony_ci} 434