1*c052d13cSHaojian Zhuang /* 2*c052d13cSHaojian Zhuang * linux/arch/arm/mach-mmp/irq.c 3*c052d13cSHaojian Zhuang * 4*c052d13cSHaojian Zhuang * Generic IRQ handling, GPIO IRQ demultiplexing, etc. 5*c052d13cSHaojian Zhuang * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd. 6*c052d13cSHaojian Zhuang * 7*c052d13cSHaojian Zhuang * Author: Bin Yang <bin.yang@marvell.com> 8*c052d13cSHaojian Zhuang * Haojian Zhuang <haojian.zhuang@gmail.com> 9*c052d13cSHaojian Zhuang * 10*c052d13cSHaojian Zhuang * This program is free software; you can redistribute it and/or modify 11*c052d13cSHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 12*c052d13cSHaojian Zhuang * published by the Free Software Foundation. 13*c052d13cSHaojian Zhuang */ 14*c052d13cSHaojian Zhuang 15*c052d13cSHaojian Zhuang #include <linux/module.h> 16*c052d13cSHaojian Zhuang #include <linux/init.h> 17*c052d13cSHaojian Zhuang #include <linux/irq.h> 18*c052d13cSHaojian Zhuang #include <linux/irqdomain.h> 19*c052d13cSHaojian Zhuang #include <linux/io.h> 20*c052d13cSHaojian Zhuang #include <linux/ioport.h> 21*c052d13cSHaojian Zhuang #include <linux/of_address.h> 22*c052d13cSHaojian Zhuang #include <linux/of_irq.h> 23*c052d13cSHaojian Zhuang 24*c052d13cSHaojian Zhuang #include <mach/irqs.h> 25*c052d13cSHaojian Zhuang 26*c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_MMP2 27*c052d13cSHaojian Zhuang #include <mach/pm-mmp2.h> 28*c052d13cSHaojian Zhuang #endif 29*c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_PXA910 30*c052d13cSHaojian Zhuang #include <mach/pm-pxa910.h> 31*c052d13cSHaojian Zhuang #endif 32*c052d13cSHaojian Zhuang 33*c052d13cSHaojian Zhuang #define MAX_ICU_NR 16 34*c052d13cSHaojian Zhuang 35*c052d13cSHaojian Zhuang struct icu_chip_data { 36*c052d13cSHaojian Zhuang int nr_irqs; 37*c052d13cSHaojian Zhuang unsigned int virq_base; 38*c052d13cSHaojian Zhuang unsigned int cascade_irq; 39*c052d13cSHaojian Zhuang void __iomem *reg_status; 40*c052d13cSHaojian Zhuang void __iomem *reg_mask; 41*c052d13cSHaojian Zhuang unsigned int conf_enable; 42*c052d13cSHaojian Zhuang unsigned int conf_disable; 43*c052d13cSHaojian Zhuang unsigned int conf_mask; 44*c052d13cSHaojian Zhuang unsigned int clr_mfp_irq_base; 45*c052d13cSHaojian Zhuang unsigned int clr_mfp_hwirq; 46*c052d13cSHaojian Zhuang struct irq_domain *domain; 47*c052d13cSHaojian Zhuang }; 48*c052d13cSHaojian Zhuang 49*c052d13cSHaojian Zhuang struct mmp_intc_conf { 50*c052d13cSHaojian Zhuang unsigned int conf_enable; 51*c052d13cSHaojian Zhuang unsigned int conf_disable; 52*c052d13cSHaojian Zhuang unsigned int conf_mask; 53*c052d13cSHaojian Zhuang }; 54*c052d13cSHaojian Zhuang 55*c052d13cSHaojian Zhuang void __iomem *mmp_icu_base; 56*c052d13cSHaojian Zhuang static struct icu_chip_data icu_data[MAX_ICU_NR]; 57*c052d13cSHaojian Zhuang static int max_icu_nr; 58*c052d13cSHaojian Zhuang 59*c052d13cSHaojian Zhuang extern void mmp2_clear_pmic_int(void); 60*c052d13cSHaojian Zhuang 61*c052d13cSHaojian Zhuang static void icu_mask_ack_irq(struct irq_data *d) 62*c052d13cSHaojian Zhuang { 63*c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 64*c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 65*c052d13cSHaojian Zhuang int hwirq; 66*c052d13cSHaojian Zhuang u32 r; 67*c052d13cSHaojian Zhuang 68*c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 69*c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 70*c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 71*c052d13cSHaojian Zhuang r &= ~data->conf_mask; 72*c052d13cSHaojian Zhuang r |= data->conf_disable; 73*c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 74*c052d13cSHaojian Zhuang } else { 75*c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_MMP2 76*c052d13cSHaojian Zhuang if ((data->virq_base == data->clr_mfp_irq_base) 77*c052d13cSHaojian Zhuang && (hwirq == data->clr_mfp_hwirq)) 78*c052d13cSHaojian Zhuang mmp2_clear_pmic_int(); 79*c052d13cSHaojian Zhuang #endif 80*c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 81*c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 82*c052d13cSHaojian Zhuang } 83*c052d13cSHaojian Zhuang } 84*c052d13cSHaojian Zhuang 85*c052d13cSHaojian Zhuang static void icu_mask_irq(struct irq_data *d) 86*c052d13cSHaojian Zhuang { 87*c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 88*c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 89*c052d13cSHaojian Zhuang int hwirq; 90*c052d13cSHaojian Zhuang u32 r; 91*c052d13cSHaojian Zhuang 92*c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 93*c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 94*c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 95*c052d13cSHaojian Zhuang r &= ~data->conf_mask; 96*c052d13cSHaojian Zhuang r |= data->conf_disable; 97*c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 98*c052d13cSHaojian Zhuang } else { 99*c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 100*c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 101*c052d13cSHaojian Zhuang } 102*c052d13cSHaojian Zhuang } 103*c052d13cSHaojian Zhuang 104*c052d13cSHaojian Zhuang static void icu_unmask_irq(struct irq_data *d) 105*c052d13cSHaojian Zhuang { 106*c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 107*c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 108*c052d13cSHaojian Zhuang int hwirq; 109*c052d13cSHaojian Zhuang u32 r; 110*c052d13cSHaojian Zhuang 111*c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 112*c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 113*c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 114*c052d13cSHaojian Zhuang r &= ~data->conf_mask; 115*c052d13cSHaojian Zhuang r |= data->conf_enable; 116*c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 117*c052d13cSHaojian Zhuang } else { 118*c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) & ~(1 << hwirq); 119*c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 120*c052d13cSHaojian Zhuang } 121*c052d13cSHaojian Zhuang } 122*c052d13cSHaojian Zhuang 123*c052d13cSHaojian Zhuang static struct irq_chip icu_irq_chip = { 124*c052d13cSHaojian Zhuang .name = "icu_irq", 125*c052d13cSHaojian Zhuang .irq_mask = icu_mask_irq, 126*c052d13cSHaojian Zhuang .irq_mask_ack = icu_mask_ack_irq, 127*c052d13cSHaojian Zhuang .irq_unmask = icu_unmask_irq, 128*c052d13cSHaojian Zhuang }; 129*c052d13cSHaojian Zhuang 130*c052d13cSHaojian Zhuang static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc) 131*c052d13cSHaojian Zhuang { 132*c052d13cSHaojian Zhuang struct irq_domain *domain; 133*c052d13cSHaojian Zhuang struct icu_chip_data *data; 134*c052d13cSHaojian Zhuang int i; 135*c052d13cSHaojian Zhuang unsigned long mask, status, n; 136*c052d13cSHaojian Zhuang 137*c052d13cSHaojian Zhuang for (i = 1; i < max_icu_nr; i++) { 138*c052d13cSHaojian Zhuang if (irq == icu_data[i].cascade_irq) { 139*c052d13cSHaojian Zhuang domain = icu_data[i].domain; 140*c052d13cSHaojian Zhuang data = (struct icu_chip_data *)domain->host_data; 141*c052d13cSHaojian Zhuang break; 142*c052d13cSHaojian Zhuang } 143*c052d13cSHaojian Zhuang } 144*c052d13cSHaojian Zhuang if (i >= max_icu_nr) { 145*c052d13cSHaojian Zhuang pr_err("Spurious irq %d in MMP INTC\n", irq); 146*c052d13cSHaojian Zhuang return; 147*c052d13cSHaojian Zhuang } 148*c052d13cSHaojian Zhuang 149*c052d13cSHaojian Zhuang mask = readl_relaxed(data->reg_mask); 150*c052d13cSHaojian Zhuang while (1) { 151*c052d13cSHaojian Zhuang status = readl_relaxed(data->reg_status) & ~mask; 152*c052d13cSHaojian Zhuang if (status == 0) 153*c052d13cSHaojian Zhuang break; 154*c052d13cSHaojian Zhuang for_each_set_bit(n, &status, BITS_PER_LONG) { 155*c052d13cSHaojian Zhuang generic_handle_irq(icu_data[i].virq_base + n); 156*c052d13cSHaojian Zhuang } 157*c052d13cSHaojian Zhuang } 158*c052d13cSHaojian Zhuang } 159*c052d13cSHaojian Zhuang 160*c052d13cSHaojian Zhuang static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, 161*c052d13cSHaojian Zhuang irq_hw_number_t hw) 162*c052d13cSHaojian Zhuang { 163*c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 164*c052d13cSHaojian Zhuang set_irq_flags(irq, IRQF_VALID); 165*c052d13cSHaojian Zhuang return 0; 166*c052d13cSHaojian Zhuang } 167*c052d13cSHaojian Zhuang 168*c052d13cSHaojian Zhuang static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node, 169*c052d13cSHaojian Zhuang const u32 *intspec, unsigned int intsize, 170*c052d13cSHaojian Zhuang unsigned long *out_hwirq, 171*c052d13cSHaojian Zhuang unsigned int *out_type) 172*c052d13cSHaojian Zhuang { 173*c052d13cSHaojian Zhuang *out_hwirq = intspec[0]; 174*c052d13cSHaojian Zhuang return 0; 175*c052d13cSHaojian Zhuang } 176*c052d13cSHaojian Zhuang 177*c052d13cSHaojian Zhuang const struct irq_domain_ops mmp_irq_domain_ops = { 178*c052d13cSHaojian Zhuang .map = mmp_irq_domain_map, 179*c052d13cSHaojian Zhuang .xlate = mmp_irq_domain_xlate, 180*c052d13cSHaojian Zhuang }; 181*c052d13cSHaojian Zhuang 182*c052d13cSHaojian Zhuang static struct mmp_intc_conf mmp_conf = { 183*c052d13cSHaojian Zhuang .conf_enable = 0x51, 184*c052d13cSHaojian Zhuang .conf_disable = 0x0, 185*c052d13cSHaojian Zhuang .conf_mask = 0x7f, 186*c052d13cSHaojian Zhuang }; 187*c052d13cSHaojian Zhuang 188*c052d13cSHaojian Zhuang static struct mmp_intc_conf mmp2_conf = { 189*c052d13cSHaojian Zhuang .conf_enable = 0x20, 190*c052d13cSHaojian Zhuang .conf_disable = 0x0, 191*c052d13cSHaojian Zhuang .conf_mask = 0x7f, 192*c052d13cSHaojian Zhuang }; 193*c052d13cSHaojian Zhuang 194*c052d13cSHaojian Zhuang /* MMP (ARMv5) */ 195*c052d13cSHaojian Zhuang void __init icu_init_irq(void) 196*c052d13cSHaojian Zhuang { 197*c052d13cSHaojian Zhuang int irq; 198*c052d13cSHaojian Zhuang 199*c052d13cSHaojian Zhuang max_icu_nr = 1; 200*c052d13cSHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 201*c052d13cSHaojian Zhuang icu_data[0].conf_enable = mmp_conf.conf_enable; 202*c052d13cSHaojian Zhuang icu_data[0].conf_disable = mmp_conf.conf_disable; 203*c052d13cSHaojian Zhuang icu_data[0].conf_mask = mmp_conf.conf_mask; 204*c052d13cSHaojian Zhuang icu_data[0].nr_irqs = 64; 205*c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 206*c052d13cSHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 207*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 208*c052d13cSHaojian Zhuang &icu_data[0]); 209*c052d13cSHaojian Zhuang for (irq = 0; irq < 64; irq++) { 210*c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 211*c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 212*c052d13cSHaojian Zhuang set_irq_flags(irq, IRQF_VALID); 213*c052d13cSHaojian Zhuang } 214*c052d13cSHaojian Zhuang irq_set_default_host(icu_data[0].domain); 215*c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_PXA910 216*c052d13cSHaojian Zhuang icu_irq_chip.irq_set_wake = pxa910_set_wake; 217*c052d13cSHaojian Zhuang #endif 218*c052d13cSHaojian Zhuang } 219*c052d13cSHaojian Zhuang 220*c052d13cSHaojian Zhuang /* MMP2 (ARMv7) */ 221*c052d13cSHaojian Zhuang void __init mmp2_init_icu(void) 222*c052d13cSHaojian Zhuang { 223*c052d13cSHaojian Zhuang int irq; 224*c052d13cSHaojian Zhuang 225*c052d13cSHaojian Zhuang max_icu_nr = 8; 226*c052d13cSHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 227*c052d13cSHaojian Zhuang icu_data[0].conf_enable = mmp2_conf.conf_enable; 228*c052d13cSHaojian Zhuang icu_data[0].conf_disable = mmp2_conf.conf_disable; 229*c052d13cSHaojian Zhuang icu_data[0].conf_mask = mmp2_conf.conf_mask; 230*c052d13cSHaojian Zhuang icu_data[0].nr_irqs = 64; 231*c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 232*c052d13cSHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 233*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 234*c052d13cSHaojian Zhuang &icu_data[0]); 235*c052d13cSHaojian Zhuang icu_data[1].reg_status = mmp_icu_base + 0x150; 236*c052d13cSHaojian Zhuang icu_data[1].reg_mask = mmp_icu_base + 0x168; 237*c052d13cSHaojian Zhuang icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE; 238*c052d13cSHaojian Zhuang icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE; 239*c052d13cSHaojian Zhuang icu_data[1].nr_irqs = 2; 240*c052d13cSHaojian Zhuang icu_data[1].cascade_irq = 4; 241*c052d13cSHaojian Zhuang icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE; 242*c052d13cSHaojian Zhuang icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs, 243*c052d13cSHaojian Zhuang icu_data[1].virq_base, 0, 244*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 245*c052d13cSHaojian Zhuang &icu_data[1]); 246*c052d13cSHaojian Zhuang icu_data[2].reg_status = mmp_icu_base + 0x154; 247*c052d13cSHaojian Zhuang icu_data[2].reg_mask = mmp_icu_base + 0x16c; 248*c052d13cSHaojian Zhuang icu_data[2].nr_irqs = 2; 249*c052d13cSHaojian Zhuang icu_data[2].cascade_irq = 5; 250*c052d13cSHaojian Zhuang icu_data[2].virq_base = IRQ_MMP2_RTC_BASE; 251*c052d13cSHaojian Zhuang icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs, 252*c052d13cSHaojian Zhuang icu_data[2].virq_base, 0, 253*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 254*c052d13cSHaojian Zhuang &icu_data[2]); 255*c052d13cSHaojian Zhuang icu_data[3].reg_status = mmp_icu_base + 0x180; 256*c052d13cSHaojian Zhuang icu_data[3].reg_mask = mmp_icu_base + 0x17c; 257*c052d13cSHaojian Zhuang icu_data[3].nr_irqs = 3; 258*c052d13cSHaojian Zhuang icu_data[3].cascade_irq = 9; 259*c052d13cSHaojian Zhuang icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE; 260*c052d13cSHaojian Zhuang icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs, 261*c052d13cSHaojian Zhuang icu_data[3].virq_base, 0, 262*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 263*c052d13cSHaojian Zhuang &icu_data[3]); 264*c052d13cSHaojian Zhuang icu_data[4].reg_status = mmp_icu_base + 0x158; 265*c052d13cSHaojian Zhuang icu_data[4].reg_mask = mmp_icu_base + 0x170; 266*c052d13cSHaojian Zhuang icu_data[4].nr_irqs = 5; 267*c052d13cSHaojian Zhuang icu_data[4].cascade_irq = 17; 268*c052d13cSHaojian Zhuang icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE; 269*c052d13cSHaojian Zhuang icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs, 270*c052d13cSHaojian Zhuang icu_data[4].virq_base, 0, 271*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 272*c052d13cSHaojian Zhuang &icu_data[4]); 273*c052d13cSHaojian Zhuang icu_data[5].reg_status = mmp_icu_base + 0x15c; 274*c052d13cSHaojian Zhuang icu_data[5].reg_mask = mmp_icu_base + 0x174; 275*c052d13cSHaojian Zhuang icu_data[5].nr_irqs = 15; 276*c052d13cSHaojian Zhuang icu_data[5].cascade_irq = 35; 277*c052d13cSHaojian Zhuang icu_data[5].virq_base = IRQ_MMP2_MISC_BASE; 278*c052d13cSHaojian Zhuang icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs, 279*c052d13cSHaojian Zhuang icu_data[5].virq_base, 0, 280*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 281*c052d13cSHaojian Zhuang &icu_data[5]); 282*c052d13cSHaojian Zhuang icu_data[6].reg_status = mmp_icu_base + 0x160; 283*c052d13cSHaojian Zhuang icu_data[6].reg_mask = mmp_icu_base + 0x178; 284*c052d13cSHaojian Zhuang icu_data[6].nr_irqs = 2; 285*c052d13cSHaojian Zhuang icu_data[6].cascade_irq = 51; 286*c052d13cSHaojian Zhuang icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE; 287*c052d13cSHaojian Zhuang icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs, 288*c052d13cSHaojian Zhuang icu_data[6].virq_base, 0, 289*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 290*c052d13cSHaojian Zhuang &icu_data[6]); 291*c052d13cSHaojian Zhuang icu_data[7].reg_status = mmp_icu_base + 0x188; 292*c052d13cSHaojian Zhuang icu_data[7].reg_mask = mmp_icu_base + 0x184; 293*c052d13cSHaojian Zhuang icu_data[7].nr_irqs = 2; 294*c052d13cSHaojian Zhuang icu_data[7].cascade_irq = 55; 295*c052d13cSHaojian Zhuang icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE; 296*c052d13cSHaojian Zhuang icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs, 297*c052d13cSHaojian Zhuang icu_data[7].virq_base, 0, 298*c052d13cSHaojian Zhuang &irq_domain_simple_ops, 299*c052d13cSHaojian Zhuang &icu_data[7]); 300*c052d13cSHaojian Zhuang for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) { 301*c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 302*c052d13cSHaojian Zhuang switch (irq) { 303*c052d13cSHaojian Zhuang case IRQ_MMP2_PMIC_MUX: 304*c052d13cSHaojian Zhuang case IRQ_MMP2_RTC_MUX: 305*c052d13cSHaojian Zhuang case IRQ_MMP2_KEYPAD_MUX: 306*c052d13cSHaojian Zhuang case IRQ_MMP2_TWSI_MUX: 307*c052d13cSHaojian Zhuang case IRQ_MMP2_MISC_MUX: 308*c052d13cSHaojian Zhuang case IRQ_MMP2_MIPI_HSI1_MUX: 309*c052d13cSHaojian Zhuang case IRQ_MMP2_MIPI_HSI0_MUX: 310*c052d13cSHaojian Zhuang irq_set_chip(irq, &icu_irq_chip); 311*c052d13cSHaojian Zhuang irq_set_chained_handler(irq, icu_mux_irq_demux); 312*c052d13cSHaojian Zhuang break; 313*c052d13cSHaojian Zhuang default: 314*c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, 315*c052d13cSHaojian Zhuang handle_level_irq); 316*c052d13cSHaojian Zhuang break; 317*c052d13cSHaojian Zhuang } 318*c052d13cSHaojian Zhuang set_irq_flags(irq, IRQF_VALID); 319*c052d13cSHaojian Zhuang } 320*c052d13cSHaojian Zhuang irq_set_default_host(icu_data[0].domain); 321*c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_MMP2 322*c052d13cSHaojian Zhuang icu_irq_chip.irq_set_wake = mmp2_set_wake; 323*c052d13cSHaojian Zhuang #endif 324*c052d13cSHaojian Zhuang } 325*c052d13cSHaojian Zhuang 326*c052d13cSHaojian Zhuang #ifdef CONFIG_OF 327*c052d13cSHaojian Zhuang static const struct of_device_id intc_ids[] __initconst = { 328*c052d13cSHaojian Zhuang { .compatible = "mrvl,mmp-intc", .data = &mmp_conf }, 329*c052d13cSHaojian Zhuang { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf }, 330*c052d13cSHaojian Zhuang {} 331*c052d13cSHaojian Zhuang }; 332*c052d13cSHaojian Zhuang 333*c052d13cSHaojian Zhuang static const struct of_device_id mmp_mux_irq_match[] __initconst = { 334*c052d13cSHaojian Zhuang { .compatible = "mrvl,mmp2-mux-intc" }, 335*c052d13cSHaojian Zhuang {} 336*c052d13cSHaojian Zhuang }; 337*c052d13cSHaojian Zhuang 338*c052d13cSHaojian Zhuang int __init mmp2_mux_init(struct device_node *parent) 339*c052d13cSHaojian Zhuang { 340*c052d13cSHaojian Zhuang struct device_node *node; 341*c052d13cSHaojian Zhuang const struct of_device_id *of_id; 342*c052d13cSHaojian Zhuang struct resource res; 343*c052d13cSHaojian Zhuang int i, irq_base, ret, irq; 344*c052d13cSHaojian Zhuang u32 nr_irqs, mfp_irq; 345*c052d13cSHaojian Zhuang 346*c052d13cSHaojian Zhuang node = parent; 347*c052d13cSHaojian Zhuang max_icu_nr = 1; 348*c052d13cSHaojian Zhuang for (i = 1; i < MAX_ICU_NR; i++) { 349*c052d13cSHaojian Zhuang node = of_find_matching_node(node, mmp_mux_irq_match); 350*c052d13cSHaojian Zhuang if (!node) 351*c052d13cSHaojian Zhuang break; 352*c052d13cSHaojian Zhuang of_id = of_match_node(&mmp_mux_irq_match[0], node); 353*c052d13cSHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", 354*c052d13cSHaojian Zhuang &nr_irqs); 355*c052d13cSHaojian Zhuang if (ret) { 356*c052d13cSHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 357*c052d13cSHaojian Zhuang ret = -EINVAL; 358*c052d13cSHaojian Zhuang goto err; 359*c052d13cSHaojian Zhuang } 360*c052d13cSHaojian Zhuang ret = of_address_to_resource(node, 0, &res); 361*c052d13cSHaojian Zhuang if (ret < 0) { 362*c052d13cSHaojian Zhuang pr_err("Not found reg property\n"); 363*c052d13cSHaojian Zhuang ret = -EINVAL; 364*c052d13cSHaojian Zhuang goto err; 365*c052d13cSHaojian Zhuang } 366*c052d13cSHaojian Zhuang icu_data[i].reg_status = mmp_icu_base + res.start; 367*c052d13cSHaojian Zhuang ret = of_address_to_resource(node, 1, &res); 368*c052d13cSHaojian Zhuang if (ret < 0) { 369*c052d13cSHaojian Zhuang pr_err("Not found reg property\n"); 370*c052d13cSHaojian Zhuang ret = -EINVAL; 371*c052d13cSHaojian Zhuang goto err; 372*c052d13cSHaojian Zhuang } 373*c052d13cSHaojian Zhuang icu_data[i].reg_mask = mmp_icu_base + res.start; 374*c052d13cSHaojian Zhuang icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); 375*c052d13cSHaojian Zhuang if (!icu_data[i].cascade_irq) { 376*c052d13cSHaojian Zhuang ret = -EINVAL; 377*c052d13cSHaojian Zhuang goto err; 378*c052d13cSHaojian Zhuang } 379*c052d13cSHaojian Zhuang 380*c052d13cSHaojian Zhuang irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); 381*c052d13cSHaojian Zhuang if (irq_base < 0) { 382*c052d13cSHaojian Zhuang pr_err("Failed to allocate IRQ numbers for mux intc\n"); 383*c052d13cSHaojian Zhuang ret = irq_base; 384*c052d13cSHaojian Zhuang goto err; 385*c052d13cSHaojian Zhuang } 386*c052d13cSHaojian Zhuang if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", 387*c052d13cSHaojian Zhuang &mfp_irq)) { 388*c052d13cSHaojian Zhuang icu_data[i].clr_mfp_irq_base = irq_base; 389*c052d13cSHaojian Zhuang icu_data[i].clr_mfp_hwirq = mfp_irq; 390*c052d13cSHaojian Zhuang } 391*c052d13cSHaojian Zhuang irq_set_chained_handler(icu_data[i].cascade_irq, 392*c052d13cSHaojian Zhuang icu_mux_irq_demux); 393*c052d13cSHaojian Zhuang icu_data[i].nr_irqs = nr_irqs; 394*c052d13cSHaojian Zhuang icu_data[i].virq_base = irq_base; 395*c052d13cSHaojian Zhuang icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs, 396*c052d13cSHaojian Zhuang irq_base, 0, 397*c052d13cSHaojian Zhuang &mmp_irq_domain_ops, 398*c052d13cSHaojian Zhuang &icu_data[i]); 399*c052d13cSHaojian Zhuang for (irq = irq_base; irq < irq_base + nr_irqs; irq++) 400*c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 401*c052d13cSHaojian Zhuang } 402*c052d13cSHaojian Zhuang max_icu_nr = i; 403*c052d13cSHaojian Zhuang return 0; 404*c052d13cSHaojian Zhuang err: 405*c052d13cSHaojian Zhuang of_node_put(node); 406*c052d13cSHaojian Zhuang max_icu_nr = i; 407*c052d13cSHaojian Zhuang return ret; 408*c052d13cSHaojian Zhuang } 409*c052d13cSHaojian Zhuang 410*c052d13cSHaojian Zhuang void __init mmp_dt_irq_init(void) 411*c052d13cSHaojian Zhuang { 412*c052d13cSHaojian Zhuang struct device_node *node; 413*c052d13cSHaojian Zhuang const struct of_device_id *of_id; 414*c052d13cSHaojian Zhuang struct mmp_intc_conf *conf; 415*c052d13cSHaojian Zhuang int nr_irqs, irq_base, ret, irq; 416*c052d13cSHaojian Zhuang 417*c052d13cSHaojian Zhuang node = of_find_matching_node(NULL, intc_ids); 418*c052d13cSHaojian Zhuang if (!node) { 419*c052d13cSHaojian Zhuang pr_err("Failed to find interrupt controller in arch-mmp\n"); 420*c052d13cSHaojian Zhuang return; 421*c052d13cSHaojian Zhuang } 422*c052d13cSHaojian Zhuang of_id = of_match_node(intc_ids, node); 423*c052d13cSHaojian Zhuang conf = of_id->data; 424*c052d13cSHaojian Zhuang 425*c052d13cSHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); 426*c052d13cSHaojian Zhuang if (ret) { 427*c052d13cSHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 428*c052d13cSHaojian Zhuang return; 429*c052d13cSHaojian Zhuang } 430*c052d13cSHaojian Zhuang 431*c052d13cSHaojian Zhuang mmp_icu_base = of_iomap(node, 0); 432*c052d13cSHaojian Zhuang if (!mmp_icu_base) { 433*c052d13cSHaojian Zhuang pr_err("Failed to get interrupt controller register\n"); 434*c052d13cSHaojian Zhuang return; 435*c052d13cSHaojian Zhuang } 436*c052d13cSHaojian Zhuang 437*c052d13cSHaojian Zhuang irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0); 438*c052d13cSHaojian Zhuang if (irq_base < 0) { 439*c052d13cSHaojian Zhuang pr_err("Failed to allocate IRQ numbers\n"); 440*c052d13cSHaojian Zhuang goto err; 441*c052d13cSHaojian Zhuang } else if (irq_base != NR_IRQS_LEGACY) { 442*c052d13cSHaojian Zhuang pr_err("ICU's irqbase should be started from 0\n"); 443*c052d13cSHaojian Zhuang goto err; 444*c052d13cSHaojian Zhuang } 445*c052d13cSHaojian Zhuang icu_data[0].conf_enable = conf->conf_enable; 446*c052d13cSHaojian Zhuang icu_data[0].conf_disable = conf->conf_disable; 447*c052d13cSHaojian Zhuang icu_data[0].conf_mask = conf->conf_mask; 448*c052d13cSHaojian Zhuang icu_data[0].nr_irqs = nr_irqs; 449*c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 450*c052d13cSHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0, 451*c052d13cSHaojian Zhuang &mmp_irq_domain_ops, 452*c052d13cSHaojian Zhuang &icu_data[0]); 453*c052d13cSHaojian Zhuang irq_set_default_host(icu_data[0].domain); 454*c052d13cSHaojian Zhuang for (irq = 0; irq < nr_irqs; irq++) 455*c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 456*c052d13cSHaojian Zhuang mmp2_mux_init(node); 457*c052d13cSHaojian Zhuang return; 458*c052d13cSHaojian Zhuang err: 459*c052d13cSHaojian Zhuang iounmap(mmp_icu_base); 460*c052d13cSHaojian Zhuang } 461*c052d13cSHaojian Zhuang #endif 462