1c24b3114SHaojian Zhuang /* 2c24b3114SHaojian Zhuang * linux/arch/arm/mach-mmp/irq.c 3c24b3114SHaojian Zhuang * 4c24b3114SHaojian Zhuang * Generic IRQ handling, GPIO IRQ demultiplexing, etc. 5c24b3114SHaojian Zhuang * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd. 6c24b3114SHaojian Zhuang * 7c24b3114SHaojian Zhuang * Author: Bin Yang <bin.yang@marvell.com> 8c24b3114SHaojian Zhuang * Haojian Zhuang <haojian.zhuang@gmail.com> 9c24b3114SHaojian Zhuang * 10c24b3114SHaojian Zhuang * This program is free software; you can redistribute it and/or modify 11c24b3114SHaojian Zhuang * it under the terms of the GNU General Public License version 2 as 12c24b3114SHaojian Zhuang * published by the Free Software Foundation. 13c24b3114SHaojian Zhuang */ 14c24b3114SHaojian Zhuang 15c24b3114SHaojian Zhuang #include <linux/module.h> 16c24b3114SHaojian Zhuang #include <linux/init.h> 17c24b3114SHaojian Zhuang #include <linux/irq.h> 1841a83e06SJoel Porquet #include <linux/irqchip.h> 19c24b3114SHaojian Zhuang #include <linux/irqdomain.h> 20c24b3114SHaojian Zhuang #include <linux/io.h> 21c24b3114SHaojian Zhuang #include <linux/ioport.h> 22c24b3114SHaojian Zhuang #include <linux/of_address.h> 23c24b3114SHaojian Zhuang #include <linux/of_irq.h> 24c24b3114SHaojian Zhuang 250f374561SHaojian Zhuang #include <asm/exception.h> 2613dde818SNeil Zhang #include <asm/hardirq.h> 270f374561SHaojian Zhuang 28c24b3114SHaojian Zhuang #define MAX_ICU_NR 16 29c24b3114SHaojian Zhuang 300f374561SHaojian Zhuang #define PJ1_INT_SEL 0x10c 310f374561SHaojian Zhuang #define PJ4_INT_SEL 0x104 320f374561SHaojian Zhuang 330f374561SHaojian Zhuang /* bit fields in PJ1_INT_SEL and PJ4_INT_SEL */ 340f374561SHaojian Zhuang #define SEL_INT_PENDING (1 << 6) 350f374561SHaojian Zhuang #define SEL_INT_NUM_MASK 0x3f 360f374561SHaojian Zhuang 372380a22bSLubomir Rintel #define MMP2_ICU_INT_ROUTE_PJ4_IRQ (1 << 5) 382380a22bSLubomir Rintel #define MMP2_ICU_INT_ROUTE_PJ4_FIQ (1 << 6) 392380a22bSLubomir Rintel 40c24b3114SHaojian Zhuang struct icu_chip_data { 41c24b3114SHaojian Zhuang int nr_irqs; 42c24b3114SHaojian Zhuang unsigned int virq_base; 43c24b3114SHaojian Zhuang unsigned int cascade_irq; 44c24b3114SHaojian Zhuang void __iomem *reg_status; 45c24b3114SHaojian Zhuang void __iomem *reg_mask; 46c24b3114SHaojian Zhuang unsigned int conf_enable; 47c24b3114SHaojian Zhuang unsigned int conf_disable; 48c24b3114SHaojian Zhuang unsigned int conf_mask; 49c24b3114SHaojian Zhuang unsigned int clr_mfp_irq_base; 50c24b3114SHaojian Zhuang unsigned int clr_mfp_hwirq; 51c24b3114SHaojian Zhuang struct irq_domain *domain; 52c24b3114SHaojian Zhuang }; 53c24b3114SHaojian Zhuang 54c24b3114SHaojian Zhuang struct mmp_intc_conf { 55c24b3114SHaojian Zhuang unsigned int conf_enable; 56c24b3114SHaojian Zhuang unsigned int conf_disable; 57c24b3114SHaojian Zhuang unsigned int conf_mask; 58c24b3114SHaojian Zhuang }; 59c24b3114SHaojian Zhuang 600f374561SHaojian Zhuang static void __iomem *mmp_icu_base; 61c24b3114SHaojian Zhuang static struct icu_chip_data icu_data[MAX_ICU_NR]; 62c24b3114SHaojian Zhuang static int max_icu_nr; 63c24b3114SHaojian Zhuang 64c24b3114SHaojian Zhuang extern void mmp2_clear_pmic_int(void); 65c24b3114SHaojian Zhuang 66c24b3114SHaojian Zhuang static void icu_mask_ack_irq(struct irq_data *d) 67c24b3114SHaojian Zhuang { 68c24b3114SHaojian Zhuang struct irq_domain *domain = d->domain; 69c24b3114SHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 70c24b3114SHaojian Zhuang int hwirq; 71c24b3114SHaojian Zhuang u32 r; 72c24b3114SHaojian Zhuang 73c24b3114SHaojian Zhuang hwirq = d->irq - data->virq_base; 74c24b3114SHaojian Zhuang if (data == &icu_data[0]) { 75c24b3114SHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 76c24b3114SHaojian Zhuang r &= ~data->conf_mask; 77c24b3114SHaojian Zhuang r |= data->conf_disable; 78c24b3114SHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 79c24b3114SHaojian Zhuang } else { 80c24b3114SHaojian Zhuang #ifdef CONFIG_CPU_MMP2 81c24b3114SHaojian Zhuang if ((data->virq_base == data->clr_mfp_irq_base) 82c24b3114SHaojian Zhuang && (hwirq == data->clr_mfp_hwirq)) 83c24b3114SHaojian Zhuang mmp2_clear_pmic_int(); 84c24b3114SHaojian Zhuang #endif 85c24b3114SHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 86c24b3114SHaojian Zhuang writel_relaxed(r, data->reg_mask); 87c24b3114SHaojian Zhuang } 88c24b3114SHaojian Zhuang } 89c24b3114SHaojian Zhuang 90c24b3114SHaojian Zhuang static void icu_mask_irq(struct irq_data *d) 91c24b3114SHaojian Zhuang { 92c24b3114SHaojian Zhuang struct irq_domain *domain = d->domain; 93c24b3114SHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 94c24b3114SHaojian Zhuang int hwirq; 95c24b3114SHaojian Zhuang u32 r; 96c24b3114SHaojian Zhuang 97c24b3114SHaojian Zhuang hwirq = d->irq - data->virq_base; 98c24b3114SHaojian Zhuang if (data == &icu_data[0]) { 99c24b3114SHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 100c24b3114SHaojian Zhuang r &= ~data->conf_mask; 101c24b3114SHaojian Zhuang r |= data->conf_disable; 102c24b3114SHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 103c24b3114SHaojian Zhuang } else { 104c24b3114SHaojian Zhuang r = readl_relaxed(data->reg_mask) | (1 << hwirq); 105c24b3114SHaojian Zhuang writel_relaxed(r, data->reg_mask); 106c24b3114SHaojian Zhuang } 107c24b3114SHaojian Zhuang } 108c24b3114SHaojian Zhuang 109c24b3114SHaojian Zhuang static void icu_unmask_irq(struct irq_data *d) 110c24b3114SHaojian Zhuang { 111c24b3114SHaojian Zhuang struct irq_domain *domain = d->domain; 112c24b3114SHaojian Zhuang struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data; 113c24b3114SHaojian Zhuang int hwirq; 114c24b3114SHaojian Zhuang u32 r; 115c24b3114SHaojian Zhuang 116c24b3114SHaojian Zhuang hwirq = d->irq - data->virq_base; 117c24b3114SHaojian Zhuang if (data == &icu_data[0]) { 118c24b3114SHaojian Zhuang r = readl_relaxed(mmp_icu_base + (hwirq << 2)); 119c24b3114SHaojian Zhuang r &= ~data->conf_mask; 120c24b3114SHaojian Zhuang r |= data->conf_enable; 121c24b3114SHaojian Zhuang writel_relaxed(r, mmp_icu_base + (hwirq << 2)); 122c24b3114SHaojian Zhuang } else { 123c24b3114SHaojian Zhuang r = readl_relaxed(data->reg_mask) & ~(1 << hwirq); 124c24b3114SHaojian Zhuang writel_relaxed(r, data->reg_mask); 125c24b3114SHaojian Zhuang } 126c24b3114SHaojian Zhuang } 127c24b3114SHaojian Zhuang 1280f102b6cSHaojian Zhuang struct irq_chip icu_irq_chip = { 129c24b3114SHaojian Zhuang .name = "icu_irq", 130c24b3114SHaojian Zhuang .irq_mask = icu_mask_irq, 131c24b3114SHaojian Zhuang .irq_mask_ack = icu_mask_ack_irq, 132c24b3114SHaojian Zhuang .irq_unmask = icu_unmask_irq, 133c24b3114SHaojian Zhuang }; 134c24b3114SHaojian Zhuang 135bd0b9ac4SThomas Gleixner static void icu_mux_irq_demux(struct irq_desc *desc) 136c24b3114SHaojian Zhuang { 13714873aa1SThomas Gleixner unsigned int irq = irq_desc_get_irq(desc); 138c24b3114SHaojian Zhuang struct irq_domain *domain; 139c24b3114SHaojian Zhuang struct icu_chip_data *data; 140c24b3114SHaojian Zhuang int i; 141c24b3114SHaojian Zhuang unsigned long mask, status, n; 142c24b3114SHaojian Zhuang 143c24b3114SHaojian Zhuang for (i = 1; i < max_icu_nr; i++) { 144c24b3114SHaojian Zhuang if (irq == icu_data[i].cascade_irq) { 145c24b3114SHaojian Zhuang domain = icu_data[i].domain; 146c24b3114SHaojian Zhuang data = (struct icu_chip_data *)domain->host_data; 147c24b3114SHaojian Zhuang break; 148c24b3114SHaojian Zhuang } 149c24b3114SHaojian Zhuang } 150c24b3114SHaojian Zhuang if (i >= max_icu_nr) { 151c24b3114SHaojian Zhuang pr_err("Spurious irq %d in MMP INTC\n", irq); 152c24b3114SHaojian Zhuang return; 153c24b3114SHaojian Zhuang } 154c24b3114SHaojian Zhuang 155c24b3114SHaojian Zhuang mask = readl_relaxed(data->reg_mask); 156c24b3114SHaojian Zhuang while (1) { 157c24b3114SHaojian Zhuang status = readl_relaxed(data->reg_status) & ~mask; 158c24b3114SHaojian Zhuang if (status == 0) 159c24b3114SHaojian Zhuang break; 16093d429a7SWei Yongjun for_each_set_bit(n, &status, BITS_PER_LONG) { 161c24b3114SHaojian Zhuang generic_handle_irq(icu_data[i].virq_base + n); 162c24b3114SHaojian Zhuang } 163c24b3114SHaojian Zhuang } 164c24b3114SHaojian Zhuang } 165c24b3114SHaojian Zhuang 166c24b3114SHaojian Zhuang static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq, 167c24b3114SHaojian Zhuang irq_hw_number_t hw) 168c24b3114SHaojian Zhuang { 169c24b3114SHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 170c24b3114SHaojian Zhuang return 0; 171c24b3114SHaojian Zhuang } 172c24b3114SHaojian Zhuang 173c24b3114SHaojian Zhuang static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node, 174c24b3114SHaojian Zhuang const u32 *intspec, unsigned int intsize, 175c24b3114SHaojian Zhuang unsigned long *out_hwirq, 176c24b3114SHaojian Zhuang unsigned int *out_type) 177c24b3114SHaojian Zhuang { 178c24b3114SHaojian Zhuang *out_hwirq = intspec[0]; 179c24b3114SHaojian Zhuang return 0; 180c24b3114SHaojian Zhuang } 181c24b3114SHaojian Zhuang 182*096048cbSYueHaibing static const struct irq_domain_ops mmp_irq_domain_ops = { 183c24b3114SHaojian Zhuang .map = mmp_irq_domain_map, 184c24b3114SHaojian Zhuang .xlate = mmp_irq_domain_xlate, 185c24b3114SHaojian Zhuang }; 186c24b3114SHaojian Zhuang 187c8c7d93dSBhumika Goyal static const struct mmp_intc_conf mmp_conf = { 188c24b3114SHaojian Zhuang .conf_enable = 0x51, 189c24b3114SHaojian Zhuang .conf_disable = 0x0, 190c24b3114SHaojian Zhuang .conf_mask = 0x7f, 191c24b3114SHaojian Zhuang }; 192c24b3114SHaojian Zhuang 193c8c7d93dSBhumika Goyal static const struct mmp_intc_conf mmp2_conf = { 194c24b3114SHaojian Zhuang .conf_enable = 0x20, 195c24b3114SHaojian Zhuang .conf_disable = 0x0, 1962380a22bSLubomir Rintel .conf_mask = MMP2_ICU_INT_ROUTE_PJ4_IRQ | 1972380a22bSLubomir Rintel MMP2_ICU_INT_ROUTE_PJ4_FIQ, 198c24b3114SHaojian Zhuang }; 199c24b3114SHaojian Zhuang 2008783dd3aSStephen Boyd static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) 2010f374561SHaojian Zhuang { 202b918402cSMarc Zyngier int hwirq; 2030f374561SHaojian Zhuang 2040f374561SHaojian Zhuang hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL); 2050f374561SHaojian Zhuang if (!(hwirq & SEL_INT_PENDING)) 2060f374561SHaojian Zhuang return; 2070f374561SHaojian Zhuang hwirq &= SEL_INT_NUM_MASK; 208b918402cSMarc Zyngier handle_domain_irq(icu_data[0].domain, hwirq, regs); 2090f374561SHaojian Zhuang } 2100f374561SHaojian Zhuang 2118783dd3aSStephen Boyd static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs) 2120f374561SHaojian Zhuang { 213b918402cSMarc Zyngier int hwirq; 2140f374561SHaojian Zhuang 2150f374561SHaojian Zhuang hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL); 2160f374561SHaojian Zhuang if (!(hwirq & SEL_INT_PENDING)) 2170f374561SHaojian Zhuang return; 2180f374561SHaojian Zhuang hwirq &= SEL_INT_NUM_MASK; 219b918402cSMarc Zyngier handle_domain_irq(icu_data[0].domain, hwirq, regs); 2200f374561SHaojian Zhuang } 2210f374561SHaojian Zhuang 222c24b3114SHaojian Zhuang /* MMP (ARMv5) */ 223c24b3114SHaojian Zhuang void __init icu_init_irq(void) 224c24b3114SHaojian Zhuang { 225c24b3114SHaojian Zhuang int irq; 226c24b3114SHaojian Zhuang 227c24b3114SHaojian Zhuang max_icu_nr = 1; 228c24b3114SHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 229c24b3114SHaojian Zhuang icu_data[0].conf_enable = mmp_conf.conf_enable; 230c24b3114SHaojian Zhuang icu_data[0].conf_disable = mmp_conf.conf_disable; 231c24b3114SHaojian Zhuang icu_data[0].conf_mask = mmp_conf.conf_mask; 232c24b3114SHaojian Zhuang icu_data[0].nr_irqs = 64; 233c24b3114SHaojian Zhuang icu_data[0].virq_base = 0; 234c24b3114SHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 235c24b3114SHaojian Zhuang &irq_domain_simple_ops, 236c24b3114SHaojian Zhuang &icu_data[0]); 237c24b3114SHaojian Zhuang for (irq = 0; irq < 64; irq++) { 238c24b3114SHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 239c24b3114SHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq); 240c24b3114SHaojian Zhuang } 241c24b3114SHaojian Zhuang irq_set_default_host(icu_data[0].domain); 2420f374561SHaojian Zhuang set_handle_irq(mmp_handle_irq); 243c24b3114SHaojian Zhuang } 244c24b3114SHaojian Zhuang 245c24b3114SHaojian Zhuang /* MMP2 (ARMv7) */ 246c24b3114SHaojian Zhuang void __init mmp2_init_icu(void) 247c24b3114SHaojian Zhuang { 248942f4221SHaojian Zhuang int irq, end; 249c24b3114SHaojian Zhuang 250c24b3114SHaojian Zhuang max_icu_nr = 8; 251c24b3114SHaojian Zhuang mmp_icu_base = ioremap(0xd4282000, 0x1000); 252c24b3114SHaojian Zhuang icu_data[0].conf_enable = mmp2_conf.conf_enable; 253c24b3114SHaojian Zhuang icu_data[0].conf_disable = mmp2_conf.conf_disable; 254c24b3114SHaojian Zhuang icu_data[0].conf_mask = mmp2_conf.conf_mask; 255c24b3114SHaojian Zhuang icu_data[0].nr_irqs = 64; 256c24b3114SHaojian Zhuang icu_data[0].virq_base = 0; 257c24b3114SHaojian Zhuang icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0, 258c24b3114SHaojian Zhuang &irq_domain_simple_ops, 259c24b3114SHaojian Zhuang &icu_data[0]); 260c24b3114SHaojian Zhuang icu_data[1].reg_status = mmp_icu_base + 0x150; 261c24b3114SHaojian Zhuang icu_data[1].reg_mask = mmp_icu_base + 0x168; 262942f4221SHaojian Zhuang icu_data[1].clr_mfp_irq_base = icu_data[0].virq_base + 263942f4221SHaojian Zhuang icu_data[0].nr_irqs; 264942f4221SHaojian Zhuang icu_data[1].clr_mfp_hwirq = 1; /* offset to IRQ_MMP2_PMIC_BASE */ 265c24b3114SHaojian Zhuang icu_data[1].nr_irqs = 2; 26610bd21c0SHaojian Zhuang icu_data[1].cascade_irq = 4; 267942f4221SHaojian Zhuang icu_data[1].virq_base = icu_data[0].virq_base + icu_data[0].nr_irqs; 268c24b3114SHaojian Zhuang icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs, 269c24b3114SHaojian Zhuang icu_data[1].virq_base, 0, 270c24b3114SHaojian Zhuang &irq_domain_simple_ops, 271c24b3114SHaojian Zhuang &icu_data[1]); 272c24b3114SHaojian Zhuang icu_data[2].reg_status = mmp_icu_base + 0x154; 273c24b3114SHaojian Zhuang icu_data[2].reg_mask = mmp_icu_base + 0x16c; 274c24b3114SHaojian Zhuang icu_data[2].nr_irqs = 2; 27510bd21c0SHaojian Zhuang icu_data[2].cascade_irq = 5; 276942f4221SHaojian Zhuang icu_data[2].virq_base = icu_data[1].virq_base + icu_data[1].nr_irqs; 277c24b3114SHaojian Zhuang icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs, 278c24b3114SHaojian Zhuang icu_data[2].virq_base, 0, 279c24b3114SHaojian Zhuang &irq_domain_simple_ops, 280c24b3114SHaojian Zhuang &icu_data[2]); 281c24b3114SHaojian Zhuang icu_data[3].reg_status = mmp_icu_base + 0x180; 282c24b3114SHaojian Zhuang icu_data[3].reg_mask = mmp_icu_base + 0x17c; 283c24b3114SHaojian Zhuang icu_data[3].nr_irqs = 3; 28410bd21c0SHaojian Zhuang icu_data[3].cascade_irq = 9; 285942f4221SHaojian Zhuang icu_data[3].virq_base = icu_data[2].virq_base + icu_data[2].nr_irqs; 286c24b3114SHaojian Zhuang icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs, 287c24b3114SHaojian Zhuang icu_data[3].virq_base, 0, 288c24b3114SHaojian Zhuang &irq_domain_simple_ops, 289c24b3114SHaojian Zhuang &icu_data[3]); 290c24b3114SHaojian Zhuang icu_data[4].reg_status = mmp_icu_base + 0x158; 291c24b3114SHaojian Zhuang icu_data[4].reg_mask = mmp_icu_base + 0x170; 292c24b3114SHaojian Zhuang icu_data[4].nr_irqs = 5; 29310bd21c0SHaojian Zhuang icu_data[4].cascade_irq = 17; 294942f4221SHaojian Zhuang icu_data[4].virq_base = icu_data[3].virq_base + icu_data[3].nr_irqs; 295c24b3114SHaojian Zhuang icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs, 296c24b3114SHaojian Zhuang icu_data[4].virq_base, 0, 297c24b3114SHaojian Zhuang &irq_domain_simple_ops, 298c24b3114SHaojian Zhuang &icu_data[4]); 299c24b3114SHaojian Zhuang icu_data[5].reg_status = mmp_icu_base + 0x15c; 300c24b3114SHaojian Zhuang icu_data[5].reg_mask = mmp_icu_base + 0x174; 301c24b3114SHaojian Zhuang icu_data[5].nr_irqs = 15; 30210bd21c0SHaojian Zhuang icu_data[5].cascade_irq = 35; 303942f4221SHaojian Zhuang icu_data[5].virq_base = icu_data[4].virq_base + icu_data[4].nr_irqs; 304c24b3114SHaojian Zhuang icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs, 305c24b3114SHaojian Zhuang icu_data[5].virq_base, 0, 306c24b3114SHaojian Zhuang &irq_domain_simple_ops, 307c24b3114SHaojian Zhuang &icu_data[5]); 308c24b3114SHaojian Zhuang icu_data[6].reg_status = mmp_icu_base + 0x160; 309c24b3114SHaojian Zhuang icu_data[6].reg_mask = mmp_icu_base + 0x178; 310c24b3114SHaojian Zhuang icu_data[6].nr_irqs = 2; 31110bd21c0SHaojian Zhuang icu_data[6].cascade_irq = 51; 312942f4221SHaojian Zhuang icu_data[6].virq_base = icu_data[5].virq_base + icu_data[5].nr_irqs; 313c24b3114SHaojian Zhuang icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs, 314c24b3114SHaojian Zhuang icu_data[6].virq_base, 0, 315c24b3114SHaojian Zhuang &irq_domain_simple_ops, 316c24b3114SHaojian Zhuang &icu_data[6]); 317c24b3114SHaojian Zhuang icu_data[7].reg_status = mmp_icu_base + 0x188; 318c24b3114SHaojian Zhuang icu_data[7].reg_mask = mmp_icu_base + 0x184; 319c24b3114SHaojian Zhuang icu_data[7].nr_irqs = 2; 32010bd21c0SHaojian Zhuang icu_data[7].cascade_irq = 55; 321942f4221SHaojian Zhuang icu_data[7].virq_base = icu_data[6].virq_base + icu_data[6].nr_irqs; 322c24b3114SHaojian Zhuang icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs, 323c24b3114SHaojian Zhuang icu_data[7].virq_base, 0, 324c24b3114SHaojian Zhuang &irq_domain_simple_ops, 325c24b3114SHaojian Zhuang &icu_data[7]); 326942f4221SHaojian Zhuang end = icu_data[7].virq_base + icu_data[7].nr_irqs; 327942f4221SHaojian Zhuang for (irq = 0; irq < end; irq++) { 328c24b3114SHaojian Zhuang icu_mask_irq(irq_get_irq_data(irq)); 329942f4221SHaojian Zhuang if (irq == icu_data[1].cascade_irq || 330942f4221SHaojian Zhuang irq == icu_data[2].cascade_irq || 331942f4221SHaojian Zhuang irq == icu_data[3].cascade_irq || 332942f4221SHaojian Zhuang irq == icu_data[4].cascade_irq || 333942f4221SHaojian Zhuang irq == icu_data[5].cascade_irq || 334942f4221SHaojian Zhuang irq == icu_data[6].cascade_irq || 335942f4221SHaojian Zhuang irq == icu_data[7].cascade_irq) { 336c24b3114SHaojian Zhuang irq_set_chip(irq, &icu_irq_chip); 337c24b3114SHaojian Zhuang irq_set_chained_handler(irq, icu_mux_irq_demux); 338942f4221SHaojian Zhuang } else { 339c24b3114SHaojian Zhuang irq_set_chip_and_handler(irq, &icu_irq_chip, 340c24b3114SHaojian Zhuang handle_level_irq); 341c24b3114SHaojian Zhuang } 342c24b3114SHaojian Zhuang } 343c24b3114SHaojian Zhuang irq_set_default_host(icu_data[0].domain); 3440f374561SHaojian Zhuang set_handle_irq(mmp2_handle_irq); 345c24b3114SHaojian Zhuang } 346c24b3114SHaojian Zhuang 347c24b3114SHaojian Zhuang #ifdef CONFIG_OF 3480f374561SHaojian Zhuang static int __init mmp_init_bases(struct device_node *node) 349c24b3114SHaojian Zhuang { 3500f374561SHaojian Zhuang int ret, nr_irqs, irq, i = 0; 351c24b3114SHaojian Zhuang 352c24b3114SHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs); 353c24b3114SHaojian Zhuang if (ret) { 354c24b3114SHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 3550f374561SHaojian Zhuang return ret; 356c24b3114SHaojian Zhuang } 357c24b3114SHaojian Zhuang 358c24b3114SHaojian Zhuang mmp_icu_base = of_iomap(node, 0); 359c24b3114SHaojian Zhuang if (!mmp_icu_base) { 360c24b3114SHaojian Zhuang pr_err("Failed to get interrupt controller register\n"); 3610f374561SHaojian Zhuang return -ENOMEM; 362c24b3114SHaojian Zhuang } 363c24b3114SHaojian Zhuang 364c24b3114SHaojian Zhuang icu_data[0].virq_base = 0; 3650f374561SHaojian Zhuang icu_data[0].domain = irq_domain_add_linear(node, nr_irqs, 366c24b3114SHaojian Zhuang &mmp_irq_domain_ops, 367c24b3114SHaojian Zhuang &icu_data[0]); 3680f374561SHaojian Zhuang for (irq = 0; irq < nr_irqs; irq++) { 3690f374561SHaojian Zhuang ret = irq_create_mapping(icu_data[0].domain, irq); 3700f374561SHaojian Zhuang if (!ret) { 3710f374561SHaojian Zhuang pr_err("Failed to mapping hwirq\n"); 3720f374561SHaojian Zhuang goto err; 373c24b3114SHaojian Zhuang } 3740f374561SHaojian Zhuang if (!irq) 3750f374561SHaojian Zhuang icu_data[0].virq_base = ret; 3760f374561SHaojian Zhuang } 3770f374561SHaojian Zhuang icu_data[0].nr_irqs = nr_irqs; 3780f374561SHaojian Zhuang return 0; 3790f374561SHaojian Zhuang err: 3800f374561SHaojian Zhuang if (icu_data[0].virq_base) { 3810f374561SHaojian Zhuang for (i = 0; i < irq; i++) 3820f374561SHaojian Zhuang irq_dispose_mapping(icu_data[0].virq_base + i); 3830f374561SHaojian Zhuang } 3840f374561SHaojian Zhuang irq_domain_remove(icu_data[0].domain); 3850f374561SHaojian Zhuang iounmap(mmp_icu_base); 3860f374561SHaojian Zhuang return -EINVAL; 3870f374561SHaojian Zhuang } 3880f374561SHaojian Zhuang 3890f374561SHaojian Zhuang static int __init mmp_of_init(struct device_node *node, 3900f374561SHaojian Zhuang struct device_node *parent) 3910f374561SHaojian Zhuang { 3920f374561SHaojian Zhuang int ret; 3930f374561SHaojian Zhuang 3940f374561SHaojian Zhuang ret = mmp_init_bases(node); 3950f374561SHaojian Zhuang if (ret < 0) 3960f374561SHaojian Zhuang return ret; 3970f374561SHaojian Zhuang 3980f374561SHaojian Zhuang icu_data[0].conf_enable = mmp_conf.conf_enable; 3990f374561SHaojian Zhuang icu_data[0].conf_disable = mmp_conf.conf_disable; 4000f374561SHaojian Zhuang icu_data[0].conf_mask = mmp_conf.conf_mask; 4010f374561SHaojian Zhuang irq_set_default_host(icu_data[0].domain); 4020f374561SHaojian Zhuang set_handle_irq(mmp_handle_irq); 4030f374561SHaojian Zhuang max_icu_nr = 1; 4040f374561SHaojian Zhuang return 0; 4050f374561SHaojian Zhuang } 4060f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init); 4070f374561SHaojian Zhuang 4080f374561SHaojian Zhuang static int __init mmp2_of_init(struct device_node *node, 4090f374561SHaojian Zhuang struct device_node *parent) 4100f374561SHaojian Zhuang { 4110f374561SHaojian Zhuang int ret; 4120f374561SHaojian Zhuang 4130f374561SHaojian Zhuang ret = mmp_init_bases(node); 4140f374561SHaojian Zhuang if (ret < 0) 4150f374561SHaojian Zhuang return ret; 4160f374561SHaojian Zhuang 4170f374561SHaojian Zhuang icu_data[0].conf_enable = mmp2_conf.conf_enable; 4180f374561SHaojian Zhuang icu_data[0].conf_disable = mmp2_conf.conf_disable; 4190f374561SHaojian Zhuang icu_data[0].conf_mask = mmp2_conf.conf_mask; 4200f374561SHaojian Zhuang irq_set_default_host(icu_data[0].domain); 4210f374561SHaojian Zhuang set_handle_irq(mmp2_handle_irq); 4220f374561SHaojian Zhuang max_icu_nr = 1; 4230f374561SHaojian Zhuang return 0; 4240f374561SHaojian Zhuang } 4250f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init); 4260f374561SHaojian Zhuang 4270f374561SHaojian Zhuang static int __init mmp2_mux_of_init(struct device_node *node, 4280f374561SHaojian Zhuang struct device_node *parent) 4290f374561SHaojian Zhuang { 4300f374561SHaojian Zhuang struct resource res; 4310f374561SHaojian Zhuang int i, ret, irq, j = 0; 4320f374561SHaojian Zhuang u32 nr_irqs, mfp_irq; 4330f374561SHaojian Zhuang 4340f374561SHaojian Zhuang if (!parent) 4350f374561SHaojian Zhuang return -ENODEV; 4360f374561SHaojian Zhuang 4370f374561SHaojian Zhuang i = max_icu_nr; 4380f374561SHaojian Zhuang ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", 4390f374561SHaojian Zhuang &nr_irqs); 4400f374561SHaojian Zhuang if (ret) { 4410f374561SHaojian Zhuang pr_err("Not found mrvl,intc-nr-irqs property\n"); 4420f374561SHaojian Zhuang return -EINVAL; 4430f374561SHaojian Zhuang } 4440f374561SHaojian Zhuang ret = of_address_to_resource(node, 0, &res); 4450f374561SHaojian Zhuang if (ret < 0) { 4460f374561SHaojian Zhuang pr_err("Not found reg property\n"); 4470f374561SHaojian Zhuang return -EINVAL; 4480f374561SHaojian Zhuang } 4490f374561SHaojian Zhuang icu_data[i].reg_status = mmp_icu_base + res.start; 4500f374561SHaojian Zhuang ret = of_address_to_resource(node, 1, &res); 4510f374561SHaojian Zhuang if (ret < 0) { 4520f374561SHaojian Zhuang pr_err("Not found reg property\n"); 4530f374561SHaojian Zhuang return -EINVAL; 4540f374561SHaojian Zhuang } 4550f374561SHaojian Zhuang icu_data[i].reg_mask = mmp_icu_base + res.start; 4560f374561SHaojian Zhuang icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0); 4570f374561SHaojian Zhuang if (!icu_data[i].cascade_irq) 4580f374561SHaojian Zhuang return -EINVAL; 4590f374561SHaojian Zhuang 4600f374561SHaojian Zhuang icu_data[i].virq_base = 0; 4610f374561SHaojian Zhuang icu_data[i].domain = irq_domain_add_linear(node, nr_irqs, 4620f374561SHaojian Zhuang &mmp_irq_domain_ops, 4630f374561SHaojian Zhuang &icu_data[i]); 4640f374561SHaojian Zhuang for (irq = 0; irq < nr_irqs; irq++) { 4650f374561SHaojian Zhuang ret = irq_create_mapping(icu_data[i].domain, irq); 4660f374561SHaojian Zhuang if (!ret) { 4670f374561SHaojian Zhuang pr_err("Failed to mapping hwirq\n"); 4680f374561SHaojian Zhuang goto err; 4690f374561SHaojian Zhuang } 4700f374561SHaojian Zhuang if (!irq) 4710f374561SHaojian Zhuang icu_data[i].virq_base = ret; 4720f374561SHaojian Zhuang } 4730f374561SHaojian Zhuang icu_data[i].nr_irqs = nr_irqs; 4740f374561SHaojian Zhuang if (!of_property_read_u32(node, "mrvl,clr-mfp-irq", 4750f374561SHaojian Zhuang &mfp_irq)) { 4760f374561SHaojian Zhuang icu_data[i].clr_mfp_irq_base = icu_data[i].virq_base; 4770f374561SHaojian Zhuang icu_data[i].clr_mfp_hwirq = mfp_irq; 4780f374561SHaojian Zhuang } 4790f374561SHaojian Zhuang irq_set_chained_handler(icu_data[i].cascade_irq, 4800f374561SHaojian Zhuang icu_mux_irq_demux); 4810f374561SHaojian Zhuang max_icu_nr++; 4820f374561SHaojian Zhuang return 0; 4830f374561SHaojian Zhuang err: 4840f374561SHaojian Zhuang if (icu_data[i].virq_base) { 4850f374561SHaojian Zhuang for (j = 0; j < irq; j++) 4860f374561SHaojian Zhuang irq_dispose_mapping(icu_data[i].virq_base + j); 4870f374561SHaojian Zhuang } 4880f374561SHaojian Zhuang irq_domain_remove(icu_data[i].domain); 4890f374561SHaojian Zhuang return -EINVAL; 4900f374561SHaojian Zhuang } 4910f374561SHaojian Zhuang IRQCHIP_DECLARE(mmp2_mux_intc, "mrvl,mmp2-mux-intc", mmp2_mux_of_init); 492c24b3114SHaojian Zhuang #endif 493