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