1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2c052d13cSHaojian Zhuang /* 3c052d13cSHaojian Zhuang * linux/arch/arm/mach-mmp/irq.c 4c052d13cSHaojian Zhuang * 5c052d13cSHaojian Zhuang * Generic IRQ handling, GPIO IRQ demultiplexing, etc. 6c052d13cSHaojian Zhuang * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd. 7c052d13cSHaojian Zhuang * 8c052d13cSHaojian Zhuang * Author: Bin Yang <bin.yang@marvell.com> 9c052d13cSHaojian Zhuang * Haojian Zhuang <haojian.zhuang@gmail.com> 10c052d13cSHaojian Zhuang */ 11c052d13cSHaojian Zhuang 12c052d13cSHaojian Zhuang #include <linux/module.h> 13c052d13cSHaojian Zhuang #include <linux/init.h> 14c052d13cSHaojian Zhuang #include <linux/irq.h> 1541a83e06SJoel Porquet #include <linux/irqchip.h> 16a46bc5fdSLubomir Rintel #include <linux/irqchip/chained_irq.h> 17c052d13cSHaojian Zhuang #include <linux/irqdomain.h> 18c052d13cSHaojian Zhuang #include <linux/io.h> 19c052d13cSHaojian Zhuang #include <linux/ioport.h> 20c052d13cSHaojian Zhuang #include <linux/of_address.h> 21c052d13cSHaojian Zhuang #include <linux/of_irq.h> 22c052d13cSHaojian Zhuang 230f374561SHaojian Zhuang #include <asm/exception.h> 2413dde818SNeil Zhang #include <asm/hardirq.h> 250f374561SHaojian Zhuang 26c052d13cSHaojian Zhuang #define MAX_ICU_NR 16 27c052d13cSHaojian Zhuang 280f374561SHaojian Zhuang #define PJ1_INT_SEL 0x10c 290f374561SHaojian Zhuang #define PJ4_INT_SEL 0x104 300f374561SHaojian Zhuang 310f374561SHaojian Zhuang /* bit fields in PJ1_INT_SEL and PJ4_INT_SEL */ 320f374561SHaojian Zhuang #define SEL_INT_PENDING (1 << 6) 330f374561SHaojian Zhuang #define SEL_INT_NUM_MASK 0x3f 340f374561SHaojian Zhuang 352380a22bSLubomir Rintel #define MMP2_ICU_INT_ROUTE_PJ4_IRQ (1 << 5) 362380a22bSLubomir Rintel #define MMP2_ICU_INT_ROUTE_PJ4_FIQ (1 << 6) 372380a22bSLubomir Rintel 38c052d13cSHaojian Zhuang struct icu_chip_data { 39c052d13cSHaojian Zhuang int nr_irqs; 40c052d13cSHaojian Zhuang unsigned int virq_base; 41c052d13cSHaojian Zhuang unsigned int cascade_irq; 42c052d13cSHaojian Zhuang void __iomem *reg_status; 43c052d13cSHaojian Zhuang void __iomem *reg_mask; 44c052d13cSHaojian Zhuang unsigned int conf_enable; 45c052d13cSHaojian Zhuang unsigned int conf_disable; 46c052d13cSHaojian Zhuang unsigned int conf_mask; 47*9e8e8912SAndres Salomon unsigned int conf2_mask; 48c052d13cSHaojian Zhuang unsigned int clr_mfp_irq_base; 49c052d13cSHaojian Zhuang unsigned int clr_mfp_hwirq; 50c052d13cSHaojian Zhuang struct irq_domain *domain; 51c052d13cSHaojian Zhuang }; 52c052d13cSHaojian Zhuang 53c052d13cSHaojian Zhuang struct mmp_intc_conf { 54c052d13cSHaojian Zhuang unsigned int conf_enable; 55c052d13cSHaojian Zhuang unsigned int conf_disable; 56c052d13cSHaojian Zhuang unsigned int conf_mask; 57*9e8e8912SAndres Salomon unsigned int conf2_mask; 58c052d13cSHaojian Zhuang }; 59c052d13cSHaojian Zhuang 600f374561SHaojian Zhuang static void __iomem *mmp_icu_base; 61*9e8e8912SAndres Salomon static void __iomem *mmp_icu2_base; 62c052d13cSHaojian Zhuang static struct icu_chip_data icu_data[MAX_ICU_NR]; 63c052d13cSHaojian Zhuang static int max_icu_nr; 64c052d13cSHaojian Zhuang 65c052d13cSHaojian Zhuang extern void mmp2_clear_pmic_int(void); 66c052d13cSHaojian Zhuang 67c052d13cSHaojian Zhuang static void icu_mask_ack_irq(struct irq_data *d) 68c052d13cSHaojian Zhuang { 69c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 70c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 71c052d13cSHaojian Zhuang int hwirq; 72c052d13cSHaojian Zhuang u32 r; 73c052d13cSHaojian Zhuang 74c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 75c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 76c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 77c052d13cSHaojian Zhuang r &= ~data->conf_mask; 78c052d13cSHaojian Zhuang r |= data->conf_disable; 79c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 80c052d13cSHaojian Zhuang } else { 81c052d13cSHaojian Zhuang #ifdef CONFIG_CPU_MMP2 82c052d13cSHaojian Zhuang if ((data->virq_base == data->clr_mfp_irq_base) 83c052d13cSHaojian Zhuang && (hwirq == data->clr_mfp_hwirq)) 84c052d13cSHaojian Zhuang mmp2_clear_pmic_int(); 85c052d13cSHaojian Zhuang #endif 86c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 87c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 88c052d13cSHaojian Zhuang } 89c052d13cSHaojian Zhuang } 90c052d13cSHaojian Zhuang 91c052d13cSHaojian Zhuang static void icu_mask_irq(struct irq_data *d) 92c052d13cSHaojian Zhuang { 93c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 94c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 95c052d13cSHaojian Zhuang int hwirq; 96c052d13cSHaojian Zhuang u32 r; 97c052d13cSHaojian Zhuang 98c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 99c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 100c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 101c052d13cSHaojian Zhuang r &= ~data->conf_mask; 102c052d13cSHaojian Zhuang r |= data->conf_disable; 103c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 104*9e8e8912SAndres Salomon 105*9e8e8912SAndres Salomon if (data->conf2_mask) { 106*9e8e8912SAndres Salomon /* 107*9e8e8912SAndres Salomon * ICU1 (above) only controls PJ4 MP1; if using SMP, 108*9e8e8912SAndres Salomon * we need to also mask the MP2 and MM cores via ICU2. 109*9e8e8912SAndres Salomon */ 110*9e8e8912SAndres Salomon r = readl_relaxed(mmp_icu2_base + (hwirq << 2)); 111*9e8e8912SAndres Salomon r &= ~data->conf2_mask; 112*9e8e8912SAndres Salomon writel_relaxed(r, mmp_icu2_base + (hwirq << 2)); 113*9e8e8912SAndres Salomon } 114c052d13cSHaojian Zhuang } else { 115c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 116c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 117c052d13cSHaojian Zhuang } 118c052d13cSHaojian Zhuang } 119c052d13cSHaojian Zhuang 120c052d13cSHaojian Zhuang static void icu_unmask_irq(struct irq_data *d) 121c052d13cSHaojian Zhuang { 122c052d13cSHaojian Zhuang struct irq_domain *domain = d->domain; 123c052d13cSHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 124c052d13cSHaojian Zhuang int hwirq; 125c052d13cSHaojian Zhuang u32 r; 126c052d13cSHaojian Zhuang 127c052d13cSHaojian Zhuang hwirq = d->irq - data->virq_base; 128c052d13cSHaojian Zhuang if (data == &icu_data[0]) { 129c052d13cSHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 130c052d13cSHaojian Zhuang r &= ~data->conf_mask; 131c052d13cSHaojian Zhuang r |= data->conf_enable; 132c052d13cSHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 133c052d13cSHaojian Zhuang } else { 134c052d13cSHaojian Zhuang r = readl_relaxed(data->reg_mask) & ~(1 << hwirq); 135c052d13cSHaojian Zhuang writel_relaxed(r, data->reg_mask); 136c052d13cSHaojian Zhuang } 137c052d13cSHaojian Zhuang } 138c052d13cSHaojian Zhuang 1390f102b6cSHaojian Zhuang struct irq_chip icu_irq_chip = { 140c052d13cSHaojian Zhuang .name = "icu_irq", 141c052d13cSHaojian Zhuang .irq_mask = icu_mask_irq, 142c052d13cSHaojian Zhuang .irq_mask_ack = icu_mask_ack_irq, 143c052d13cSHaojian Zhuang .irq_unmask = icu_unmask_irq, 144c052d13cSHaojian Zhuang }; 145c052d13cSHaojian Zhuang 146bd0b9ac4SThomas Gleixner static void icu_mux_irq_demux(struct irq_desc *desc) 147c052d13cSHaojian Zhuang { 14814873aa1SThomas Gleixner unsigned int irq = irq_desc_get_irq(desc); 149a46bc5fdSLubomir Rintel struct irq_chip *chip = irq_desc_get_chip(desc); 150c052d13cSHaojian Zhuang struct irq_domain *domain; 151c052d13cSHaojian Zhuang struct icu_chip_data *data; 152c052d13cSHaojian Zhuang int i; 153c052d13cSHaojian Zhuang unsigned long mask, status, n; 154c052d13cSHaojian Zhuang 155a46bc5fdSLubomir Rintel chained_irq_enter(chip, desc); 156a46bc5fdSLubomir Rintel 157c052d13cSHaojian Zhuang for (i = 1; i < max_icu_nr; i++) { 158c052d13cSHaojian Zhuang if (irq == icu_data[i].cascade_irq) { 159c052d13cSHaojian Zhuang domain = icu_data[i].domain; 160c052d13cSHaojian Zhuang data = (struct icu_chip_data *)domain->host_data; 161c052d13cSHaojian Zhuang break; 162c052d13cSHaojian Zhuang } 163c052d13cSHaojian Zhuang } 164c052d13cSHaojian Zhuang if (i >= max_icu_nr) { 165c052d13cSHaojian Zhuang pr_err("Spurious irq %d in MMP INTC\n", irq); 166a46bc5fdSLubomir Rintel goto out; 167c052d13cSHaojian Zhuang } 168c052d13cSHaojian Zhuang 169c052d13cSHaojian Zhuang mask = readl_relaxed(data->reg_mask); 170c052d13cSHaojian Zhuang while (1) { 171c052d13cSHaojian Zhuang status = readl_relaxed(data->reg_status) & ~mask; 172c052d13cSHaojian Zhuang if (status == 0) 173c052d13cSHaojian Zhuang break; 174c052d13cSHaojian Zhuang for_each_set_bit(n, &status, BITS_PER_LONG) { 175c052d13cSHaojian Zhuang generic_handle_irq(icu_data[i].virq_base + n); 176c052d13cSHaojian Zhuang } 177c052d13cSHaojian Zhuang } 178a46bc5fdSLubomir Rintel 179a46bc5fdSLubomir Rintel out: 180a46bc5fdSLubomir Rintel chained_irq_exit(chip, desc); 181c052d13cSHaojian Zhuang } 182c052d13cSHaojian Zhuang 183c052d13cSHaojian Zhuang static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, 184c052d13cSHaojian Zhuang irq_hw_number_t hw) 185c052d13cSHaojian Zhuang { 186c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 187c052d13cSHaojian Zhuang return 0; 188c052d13cSHaojian Zhuang } 189c052d13cSHaojian Zhuang 190c052d13cSHaojian Zhuang static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node, 191c052d13cSHaojian Zhuang const u32 *intspec, unsigned int intsize, 192c052d13cSHaojian Zhuang unsigned long *out_hwirq, 193c052d13cSHaojian Zhuang unsigned int *out_type) 194c052d13cSHaojian Zhuang { 195c052d13cSHaojian Zhuang *out_hwirq = intspec[0]; 196c052d13cSHaojian Zhuang return 0; 197c052d13cSHaojian Zhuang } 198c052d13cSHaojian Zhuang 199096048cbSYueHaibing static const struct irq_domain_ops mmp_irq_domain_ops = { 200c052d13cSHaojian Zhuang .map = mmp_irq_domain_map, 201c052d13cSHaojian Zhuang .xlate = mmp_irq_domain_xlate, 202c052d13cSHaojian Zhuang }; 203c052d13cSHaojian Zhuang 204c8c7d93dSBhumika Goyal static const struct mmp_intc_conf mmp_conf = { 205c052d13cSHaojian Zhuang .conf_enable = 0x51, 206c052d13cSHaojian Zhuang .conf_disable = 0x0, 207c052d13cSHaojian Zhuang .conf_mask = 0x7f, 208c052d13cSHaojian Zhuang }; 209c052d13cSHaojian Zhuang 210c8c7d93dSBhumika Goyal static const struct mmp_intc_conf mmp2_conf = { 211c052d13cSHaojian Zhuang .conf_enable = 0x20, 212c052d13cSHaojian Zhuang .conf_disable = 0x0, 2132380a22bSLubomir Rintel .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ | 2142380a22bSLubomir Rintel MMP2_ICU_INT_ROUTE_PJ4_FIQ, 215c052d13cSHaojian Zhuang }; 216c052d13cSHaojian Zhuang 217*9e8e8912SAndres Salomon static struct mmp_intc_conf mmp3_conf = { 218*9e8e8912SAndres Salomon .conf_enable = 0x20, 219*9e8e8912SAndres Salomon .conf_disable = 0x0, 220*9e8e8912SAndres Salomon .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ | 221*9e8e8912SAndres Salomon MMP2_ICU_INT_ROUTE_PJ4_FIQ, 222*9e8e8912SAndres Salomon .conf2_mask = 0xf0, 223*9e8e8912SAndres Salomon }; 224*9e8e8912SAndres Salomon 2258783dd3aSStephen Boyd static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) 2260f374561SHaojian Zhuang { 227b918402cSMarc Zyngier int hwirq; 2280f374561SHaojian Zhuang 2290f374561SHaojian Zhuang hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL); 2300f374561SHaojian Zhuang if (!(hwirq & SEL_INT_PENDING)) 2310f374561SHaojian Zhuang return; 2320f374561SHaojian Zhuang hwirq &= SEL_INT_NUM_MASK; 233b918402cSMarc Zyngier handle_domain_irq(icu_data[0].domain, hwirq, regs); 2340f374561SHaojian Zhuang } 2350f374561SHaojian Zhuang 2368783dd3aSStephen Boyd static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs) 2370f374561SHaojian Zhuang { 238b918402cSMarc Zyngier int hwirq; 2390f374561SHaojian Zhuang 2400f374561SHaojian Zhuang hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL); 2410f374561SHaojian Zhuang if (!(hwirq & SEL_INT_PENDING)) 2420f374561SHaojian Zhuang return; 2430f374561SHaojian Zhuang hwirq &= SEL_INT_NUM_MASK; 244b918402cSMarc Zyngier handle_domain_irq(icu_data[0].domain, hwirq, regs); 2450f374561SHaojian Zhuang } 2460f374561SHaojian Zhuang 247c052d13cSHaojian Zhuang /* MMP (ARMv5) */ 248c052d13cSHaojian Zhuang void __init icu_init_irq(void) 249c052d13cSHaojian Zhuang { 250c052d13cSHaojian Zhuang int irq; 251c052d13cSHaojian Zhuang 252c052d13cSHaojian Zhuang max_icu_nr = 1; 253c052d13cSHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 254c052d13cSHaojian Zhuang icu_data[0].conf_enable = mmp_conf.conf_enable; 255c052d13cSHaojian Zhuang icu_data[0].conf_disable = mmp_conf.conf_disable; 256c052d13cSHaojian Zhuang icu_data[0].conf_mask = mmp_conf.conf_mask; 257c052d13cSHaojian Zhuang icu_data[0].nr_irqs = 64; 258c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 259c052d13cSHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 260c052d13cSHaojian Zhuang &irq_domain_simple_ops, 261c052d13cSHaojian Zhuang &icu_data[0]); 262c052d13cSHaojian Zhuang for (irq = 0; irq < 64; irq++) { 263c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 264c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 265c052d13cSHaojian Zhuang } 266c052d13cSHaojian Zhuang irq_set_default_host(icu_data[0].domain); 2670f374561SHaojian Zhuang set_handle_irq(mmp_handle_irq); 268c052d13cSHaojian Zhuang } 269c052d13cSHaojian Zhuang 270c052d13cSHaojian Zhuang /* MMP2 (ARMv7) */ 271c052d13cSHaojian Zhuang void __init mmp2_init_icu(void) 272c052d13cSHaojian Zhuang { 273942f4221SHaojian Zhuang int irq, end; 274c052d13cSHaojian Zhuang 275c052d13cSHaojian Zhuang max_icu_nr = 8; 276c052d13cSHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 277c052d13cSHaojian Zhuang icu_data[0].conf_enable = mmp2_conf.conf_enable; 278c052d13cSHaojian Zhuang icu_data[0].conf_disable = mmp2_conf.conf_disable; 279c052d13cSHaojian Zhuang icu_data[0].conf_mask = mmp2_conf.conf_mask; 280c052d13cSHaojian Zhuang icu_data[0].nr_irqs = 64; 281c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 282c052d13cSHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 283c052d13cSHaojian Zhuang &irq_domain_simple_ops, 284c052d13cSHaojian Zhuang &icu_data[0]); 285c052d13cSHaojian Zhuang icu_data[1].reg_status = mmp_icu_base + 0x150; 286c052d13cSHaojian Zhuang icu_data[1].reg_mask = mmp_icu_base + 0x168; 287942f4221SHaojian Zhuang icu_data[1].clr_mfp_irq_base = icu_data[0].virq_base + 288942f4221SHaojian Zhuang icu_data[0].nr_irqs; 289942f4221SHaojian Zhuang icu_data[1].clr_mfp_hwirq = 1; /* offset to IRQ_MMP2_PMIC_BASE */ 290c052d13cSHaojian Zhuang icu_data[1].nr_irqs = 2; 291c052d13cSHaojian Zhuang icu_data[1].cascade_irq = 4; 292942f4221SHaojian Zhuang icu_data[1].virq_base = icu_data[0].virq_base + icu_data[0].nr_irqs; 293c052d13cSHaojian Zhuang icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs, 294c052d13cSHaojian Zhuang icu_data[1].virq_base, 0, 295c052d13cSHaojian Zhuang &irq_domain_simple_ops, 296c052d13cSHaojian Zhuang &icu_data[1]); 297c052d13cSHaojian Zhuang icu_data[2].reg_status = mmp_icu_base + 0x154; 298c052d13cSHaojian Zhuang icu_data[2].reg_mask = mmp_icu_base + 0x16c; 299c052d13cSHaojian Zhuang icu_data[2].nr_irqs = 2; 300c052d13cSHaojian Zhuang icu_data[2].cascade_irq = 5; 301942f4221SHaojian Zhuang icu_data[2].virq_base = icu_data[1].virq_base + icu_data[1].nr_irqs; 302c052d13cSHaojian Zhuang icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs, 303c052d13cSHaojian Zhuang icu_data[2].virq_base, 0, 304c052d13cSHaojian Zhuang &irq_domain_simple_ops, 305c052d13cSHaojian Zhuang &icu_data[2]); 306c052d13cSHaojian Zhuang icu_data[3].reg_status = mmp_icu_base + 0x180; 307c052d13cSHaojian Zhuang icu_data[3].reg_mask = mmp_icu_base + 0x17c; 308c052d13cSHaojian Zhuang icu_data[3].nr_irqs = 3; 309c052d13cSHaojian Zhuang icu_data[3].cascade_irq = 9; 310942f4221SHaojian Zhuang icu_data[3].virq_base = icu_data[2].virq_base + icu_data[2].nr_irqs; 311c052d13cSHaojian Zhuang icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs, 312c052d13cSHaojian Zhuang icu_data[3].virq_base, 0, 313c052d13cSHaojian Zhuang &irq_domain_simple_ops, 314c052d13cSHaojian Zhuang &icu_data[3]); 315c052d13cSHaojian Zhuang icu_data[4].reg_status = mmp_icu_base + 0x158; 316c052d13cSHaojian Zhuang icu_data[4].reg_mask = mmp_icu_base + 0x170; 317c052d13cSHaojian Zhuang icu_data[4].nr_irqs = 5; 318c052d13cSHaojian Zhuang icu_data[4].cascade_irq = 17; 319942f4221SHaojian Zhuang icu_data[4].virq_base = icu_data[3].virq_base + icu_data[3].nr_irqs; 320c052d13cSHaojian Zhuang icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs, 321c052d13cSHaojian Zhuang icu_data[4].virq_base, 0, 322c052d13cSHaojian Zhuang &irq_domain_simple_ops, 323c052d13cSHaojian Zhuang &icu_data[4]); 324c052d13cSHaojian Zhuang icu_data[5].reg_status = mmp_icu_base + 0x15c; 325c052d13cSHaojian Zhuang icu_data[5].reg_mask = mmp_icu_base + 0x174; 326c052d13cSHaojian Zhuang icu_data[5].nr_irqs = 15; 327c052d13cSHaojian Zhuang icu_data[5].cascade_irq = 35; 328942f4221SHaojian Zhuang icu_data[5].virq_base = icu_data[4].virq_base + icu_data[4].nr_irqs; 329c052d13cSHaojian Zhuang icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs, 330c052d13cSHaojian Zhuang icu_data[5].virq_base, 0, 331c052d13cSHaojian Zhuang &irq_domain_simple_ops, 332c052d13cSHaojian Zhuang &icu_data[5]); 333c052d13cSHaojian Zhuang icu_data[6].reg_status = mmp_icu_base + 0x160; 334c052d13cSHaojian Zhuang icu_data[6].reg_mask = mmp_icu_base + 0x178; 335c052d13cSHaojian Zhuang icu_data[6].nr_irqs = 2; 336c052d13cSHaojian Zhuang icu_data[6].cascade_irq = 51; 337942f4221SHaojian Zhuang icu_data[6].virq_base = icu_data[5].virq_base + icu_data[5].nr_irqs; 338c052d13cSHaojian Zhuang icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs, 339c052d13cSHaojian Zhuang icu_data[6].virq_base, 0, 340c052d13cSHaojian Zhuang &irq_domain_simple_ops, 341c052d13cSHaojian Zhuang &icu_data[6]); 342c052d13cSHaojian Zhuang icu_data[7].reg_status = mmp_icu_base + 0x188; 343c052d13cSHaojian Zhuang icu_data[7].reg_mask = mmp_icu_base + 0x184; 344c052d13cSHaojian Zhuang icu_data[7].nr_irqs = 2; 345c052d13cSHaojian Zhuang icu_data[7].cascade_irq = 55; 346942f4221SHaojian Zhuang icu_data[7].virq_base = icu_data[6].virq_base + icu_data[6].nr_irqs; 347c052d13cSHaojian Zhuang icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs, 348c052d13cSHaojian Zhuang icu_data[7].virq_base, 0, 349c052d13cSHaojian Zhuang &irq_domain_simple_ops, 350c052d13cSHaojian Zhuang &icu_data[7]); 351942f4221SHaojian Zhuang end = icu_data[7].virq_base + icu_data[7].nr_irqs; 352942f4221SHaojian Zhuang for (irq = 0; irq < end; irq++) { 353c052d13cSHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 354942f4221SHaojian Zhuang if (irq == icu_data[1].cascade_irq || 355942f4221SHaojian Zhuang irq == icu_data[2].cascade_irq || 356942f4221SHaojian Zhuang irq == icu_data[3].cascade_irq || 357942f4221SHaojian Zhuang irq == icu_data[4].cascade_irq || 358942f4221SHaojian Zhuang irq == icu_data[5].cascade_irq || 359942f4221SHaojian Zhuang irq == icu_data[6].cascade_irq || 360942f4221SHaojian Zhuang irq == icu_data[7].cascade_irq) { 361c052d13cSHaojian Zhuang irq_set_chip(irq, &icu_irq_chip); 362c052d13cSHaojian Zhuang irq_set_chained_handler(irq, icu_mux_irq_demux); 363942f4221SHaojian Zhuang } else { 364c052d13cSHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, 365c052d13cSHaojian Zhuang handle_level_irq); 366c052d13cSHaojian Zhuang } 367c052d13cSHaojian Zhuang } 368c052d13cSHaojian Zhuang irq_set_default_host(icu_data[0].domain); 3690f374561SHaojian Zhuang set_handle_irq(mmp2_handle_irq); 370c052d13cSHaojian Zhuang } 371c052d13cSHaojian Zhuang 372c052d13cSHaojian Zhuang #ifdef CONFIG_OF 3730f374561SHaojian Zhuang static int __init mmp_init_bases(struct device_node *node) 374c052d13cSHaojian Zhuang { 3750f374561SHaojian Zhuang int ret, nr_irqs, irq, i = 0; 376c052d13cSHaojian Zhuang 377c052d13cSHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); 378c052d13cSHaojian Zhuang if (ret) { 379c052d13cSHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 3800f374561SHaojian Zhuang return ret; 381c052d13cSHaojian Zhuang } 382c052d13cSHaojian Zhuang 383c052d13cSHaojian Zhuang mmp_icu_base = of_iomap(node, 0); 384c052d13cSHaojian Zhuang if (!mmp_icu_base) { 385c052d13cSHaojian Zhuang pr_err("Failed to get interrupt controller register\n"); 3860f374561SHaojian Zhuang return -ENOMEM; 387c052d13cSHaojian Zhuang } 388c052d13cSHaojian Zhuang 389c052d13cSHaojian Zhuang icu_data[0].virq_base = 0; 3900f374561SHaojian Zhuang icu_data[0].domain = irq_domain_add_linear(node, nr_irqs, 391c052d13cSHaojian Zhuang &mmp_irq_domain_ops, 392c052d13cSHaojian Zhuang &icu_data[0]); 3930f374561SHaojian Zhuang for (irq = 0; irq < nr_irqs; irq++) { 3940f374561SHaojian Zhuang ret = irq_create_mapping(icu_data[0].domain, irq); 3950f374561SHaojian Zhuang if (!ret) { 3960f374561SHaojian Zhuang pr_err("Failed to mapping hwirq\n"); 3970f374561SHaojian Zhuang goto err; 398c052d13cSHaojian Zhuang } 3990f374561SHaojian Zhuang if (!irq) 4000f374561SHaojian Zhuang icu_data[0].virq_base = ret; 4010f374561SHaojian Zhuang } 4020f374561SHaojian Zhuang icu_data[0].nr_irqs = nr_irqs; 4030f374561SHaojian Zhuang return 0; 4040f374561SHaojian Zhuang err: 4050f374561SHaojian Zhuang if (icu_data[0].virq_base) { 4060f374561SHaojian Zhuang for (i = 0; i < irq; i++) 4070f374561SHaojian Zhuang irq_dispose_mapping(icu_data[0].virq_base + i); 4080f374561SHaojian Zhuang } 4090f374561SHaojian Zhuang irq_domain_remove(icu_data[0].domain); 4100f374561SHaojian Zhuang iounmap(mmp_icu_base); 4110f374561SHaojian Zhuang return -EINVAL; 4120f374561SHaojian Zhuang } 4130f374561SHaojian Zhuang 4140f374561SHaojian Zhuang static int __init mmp_of_init(struct device_node *node, 4150f374561SHaojian Zhuang struct device_node *parent) 4160f374561SHaojian Zhuang { 4170f374561SHaojian Zhuang int ret; 4180f374561SHaojian Zhuang 4190f374561SHaojian Zhuang ret = mmp_init_bases(node); 4200f374561SHaojian Zhuang if (ret < 0) 4210f374561SHaojian Zhuang return ret; 4220f374561SHaojian Zhuang 4230f374561SHaojian Zhuang icu_data[0].conf_enable = mmp_conf.conf_enable; 4240f374561SHaojian Zhuang icu_data[0].conf_disable = mmp_conf.conf_disable; 4250f374561SHaojian Zhuang icu_data[0].conf_mask = mmp_conf.conf_mask; 4260f374561SHaojian Zhuang set_handle_irq(mmp_handle_irq); 4270f374561SHaojian Zhuang max_icu_nr = 1; 4280f374561SHaojian Zhuang return 0; 4290f374561SHaojian Zhuang } 4300f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init); 4310f374561SHaojian Zhuang 4320f374561SHaojian Zhuang static int __init mmp2_of_init(struct device_node *node, 4330f374561SHaojian Zhuang struct device_node *parent) 4340f374561SHaojian Zhuang { 4350f374561SHaojian Zhuang int ret; 4360f374561SHaojian Zhuang 4370f374561SHaojian Zhuang ret = mmp_init_bases(node); 4380f374561SHaojian Zhuang if (ret < 0) 4390f374561SHaojian Zhuang return ret; 4400f374561SHaojian Zhuang 4410f374561SHaojian Zhuang icu_data[0].conf_enable = mmp2_conf.conf_enable; 4420f374561SHaojian Zhuang icu_data[0].conf_disable = mmp2_conf.conf_disable; 4430f374561SHaojian Zhuang icu_data[0].conf_mask = mmp2_conf.conf_mask; 4440f374561SHaojian Zhuang set_handle_irq(mmp2_handle_irq); 4450f374561SHaojian Zhuang max_icu_nr = 1; 4460f374561SHaojian Zhuang return 0; 4470f374561SHaojian Zhuang } 4480f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init); 4490f374561SHaojian Zhuang 450*9e8e8912SAndres Salomon static int __init mmp3_of_init(struct device_node *node, 451*9e8e8912SAndres Salomon struct device_node *parent) 452*9e8e8912SAndres Salomon { 453*9e8e8912SAndres Salomon int ret; 454*9e8e8912SAndres Salomon 455*9e8e8912SAndres Salomon mmp_icu2_base = of_iomap(node, 1); 456*9e8e8912SAndres Salomon if (!mmp_icu2_base) { 457*9e8e8912SAndres Salomon pr_err("Failed to get interrupt controller register #2\n"); 458*9e8e8912SAndres Salomon return -ENODEV; 459*9e8e8912SAndres Salomon } 460*9e8e8912SAndres Salomon 461*9e8e8912SAndres Salomon ret = mmp_init_bases(node); 462*9e8e8912SAndres Salomon if (ret < 0) { 463*9e8e8912SAndres Salomon iounmap(mmp_icu2_base); 464*9e8e8912SAndres Salomon return ret; 465*9e8e8912SAndres Salomon } 466*9e8e8912SAndres Salomon 467*9e8e8912SAndres Salomon icu_data[0].conf_enable = mmp3_conf.conf_enable; 468*9e8e8912SAndres Salomon icu_data[0].conf_disable = mmp3_conf.conf_disable; 469*9e8e8912SAndres Salomon icu_data[0].conf_mask = mmp3_conf.conf_mask; 470*9e8e8912SAndres Salomon icu_data[0].conf2_mask = mmp3_conf.conf2_mask; 471*9e8e8912SAndres Salomon set_handle_irq(mmp2_handle_irq); 472*9e8e8912SAndres Salomon max_icu_nr = 1; 473*9e8e8912SAndres Salomon return 0; 474*9e8e8912SAndres Salomon } 475*9e8e8912SAndres Salomon IRQCHIP_DECLARE(mmp3_intc, "marvell,mmp3-intc", mmp3_of_init); 476*9e8e8912SAndres Salomon 4770f374561SHaojian Zhuang static int __init mmp2_mux_of_init(struct device_node *node, 4780f374561SHaojian Zhuang struct device_node *parent) 4790f374561SHaojian Zhuang { 4800f374561SHaojian Zhuang int i, ret, irq, j = 0; 4810f374561SHaojian Zhuang u32 nr_irqs, mfp_irq; 482d6a95280SLubomir Rintel u32 reg[4]; 4830f374561SHaojian Zhuang 4840f374561SHaojian Zhuang if (!parent) 4850f374561SHaojian Zhuang return -ENODEV; 4860f374561SHaojian Zhuang 4870f374561SHaojian Zhuang i = max_icu_nr; 4880f374561SHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", 4890f374561SHaojian Zhuang &nr_irqs); 4900f374561SHaojian Zhuang if (ret) { 4910f374561SHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 4920f374561SHaojian Zhuang return -EINVAL; 4930f374561SHaojian Zhuang } 494d6a95280SLubomir Rintel 495d6a95280SLubomir Rintel /* 496d6a95280SLubomir Rintel * For historical reasons, the "regs" property of the 497d6a95280SLubomir Rintel * mrvl,mmp2-mux-intc is not a regular "regs" property containing 498d6a95280SLubomir Rintel * addresses on the parent bus, but offsets from the intc's base. 499d6a95280SLubomir Rintel * That is why we can't use of_address_to_resource() here. 500d6a95280SLubomir Rintel */ 501d6a95280SLubomir Rintel ret = of_property_read_variable_u32_array(node, "reg", reg, 502d6a95280SLubomir Rintel ARRAY_SIZE(reg), 503d6a95280SLubomir Rintel ARRAY_SIZE(reg)); 5040f374561SHaojian Zhuang if (ret < 0) { 5050f374561SHaojian Zhuang pr_err("Not found reg property\n"); 5060f374561SHaojian Zhuang return -EINVAL; 5070f374561SHaojian Zhuang } 508d6a95280SLubomir Rintel icu_data[i].reg_status = mmp_icu_base + reg[0]; 509d6a95280SLubomir Rintel icu_data[i].reg_mask = mmp_icu_base + reg[2]; 5100f374561SHaojian Zhuang icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); 5110f374561SHaojian Zhuang if (!icu_data[i].cascade_irq) 5120f374561SHaojian Zhuang return -EINVAL; 5130f374561SHaojian Zhuang 5140f374561SHaojian Zhuang icu_data[i].virq_base = 0; 5150f374561SHaojian Zhuang icu_data[i].domain = irq_domain_add_linear(node, nr_irqs, 5160f374561SHaojian Zhuang &mmp_irq_domain_ops, 5170f374561SHaojian Zhuang &icu_data[i]); 5180f374561SHaojian Zhuang for (irq = 0; irq < nr_irqs; irq++) { 5190f374561SHaojian Zhuang ret = irq_create_mapping(icu_data[i].domain, irq); 5200f374561SHaojian Zhuang if (!ret) { 5210f374561SHaojian Zhuang pr_err("Failed to mapping hwirq\n"); 5220f374561SHaojian Zhuang goto err; 5230f374561SHaojian Zhuang } 5240f374561SHaojian Zhuang if (!irq) 5250f374561SHaojian Zhuang icu_data[i].virq_base = ret; 5260f374561SHaojian Zhuang } 5270f374561SHaojian Zhuang icu_data[i].nr_irqs = nr_irqs; 5280f374561SHaojian Zhuang if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", 5290f374561SHaojian Zhuang &mfp_irq)) { 5300f374561SHaojian Zhuang icu_data[i].clr_mfp_irq_base = icu_data[i].virq_base; 5310f374561SHaojian Zhuang icu_data[i].clr_mfp_hwirq = mfp_irq; 5320f374561SHaojian Zhuang } 5330f374561SHaojian Zhuang irq_set_chained_handler(icu_data[i].cascade_irq, 5340f374561SHaojian Zhuang icu_mux_irq_demux); 5350f374561SHaojian Zhuang max_icu_nr++; 5360f374561SHaojian Zhuang return 0; 5370f374561SHaojian Zhuang err: 5380f374561SHaojian Zhuang if (icu_data[i].virq_base) { 5390f374561SHaojian Zhuang for (j = 0; j < irq; j++) 5400f374561SHaojian Zhuang irq_dispose_mapping(icu_data[i].virq_base + j); 5410f374561SHaojian Zhuang } 5420f374561SHaojian Zhuang irq_domain_remove(icu_data[i].domain); 5430f374561SHaojian Zhuang return -EINVAL; 5440f374561SHaojian Zhuang } 5450f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp2_mux_intc, "mrvl,mmp2-mux-intc", mmp2_mux_of_init); 546c052d13cSHaojian Zhuang #endif 547