144430ec0SRob Herring /* 244430ec0SRob Herring * linux/arch/arm/common/vic.c 344430ec0SRob Herring * 444430ec0SRob Herring * Copyright (C) 1999 - 2003 ARM Limited 544430ec0SRob Herring * Copyright (C) 2000 Deep Blue Solutions Ltd 644430ec0SRob Herring * 744430ec0SRob Herring * This program is free software; you can redistribute it and/or modify 844430ec0SRob Herring * it under the terms of the GNU General Public License as published by 944430ec0SRob Herring * the Free Software Foundation; either version 2 of the License, or 1044430ec0SRob Herring * (at your option) any later version. 1144430ec0SRob Herring * 1244430ec0SRob Herring * This program is distributed in the hope that it will be useful, 1344430ec0SRob Herring * but WITHOUT ANY WARRANTY; without even the implied warranty of 1444430ec0SRob Herring * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1544430ec0SRob Herring * GNU General Public License for more details. 1644430ec0SRob Herring * 1744430ec0SRob Herring * You should have received a copy of the GNU General Public License 1844430ec0SRob Herring * along with this program; if not, write to the Free Software 1944430ec0SRob Herring * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2044430ec0SRob Herring */ 2144430ec0SRob Herring 2244430ec0SRob Herring #include <linux/export.h> 2344430ec0SRob Herring #include <linux/init.h> 2444430ec0SRob Herring #include <linux/list.h> 2544430ec0SRob Herring #include <linux/io.h> 26bc895b59SOlof Johansson #include <linux/irq.h> 2744430ec0SRob Herring #include <linux/irqdomain.h> 2844430ec0SRob Herring #include <linux/of.h> 2944430ec0SRob Herring #include <linux/of_address.h> 3044430ec0SRob Herring #include <linux/of_irq.h> 3144430ec0SRob Herring #include <linux/syscore_ops.h> 3244430ec0SRob Herring #include <linux/device.h> 3344430ec0SRob Herring #include <linux/amba/bus.h> 349e47b8bfSRob Herring #include <linux/irqchip/arm-vic.h> 3544430ec0SRob Herring 3644430ec0SRob Herring #include <asm/exception.h> 37f36a3bb1SCatalin Marinas #include <asm/irq.h> 3844430ec0SRob Herring 3944430ec0SRob Herring #include "irqchip.h" 4044430ec0SRob Herring 4144430ec0SRob Herring #define VIC_IRQ_STATUS 0x00 4244430ec0SRob Herring #define VIC_FIQ_STATUS 0x04 4344430ec0SRob Herring #define VIC_INT_SELECT 0x0c /* 1 = FIQ, 0 = IRQ */ 4444430ec0SRob Herring #define VIC_INT_SOFT 0x18 4544430ec0SRob Herring #define VIC_INT_SOFT_CLEAR 0x1c 4644430ec0SRob Herring #define VIC_PROTECT 0x20 4744430ec0SRob Herring #define VIC_PL190_VECT_ADDR 0x30 /* PL190 only */ 4844430ec0SRob Herring #define VIC_PL190_DEF_VECT_ADDR 0x34 /* PL190 only */ 4944430ec0SRob Herring 5044430ec0SRob Herring #define VIC_VECT_ADDR0 0x100 /* 0 to 15 (0..31 PL192) */ 5144430ec0SRob Herring #define VIC_VECT_CNTL0 0x200 /* 0 to 15 (0..31 PL192) */ 5244430ec0SRob Herring #define VIC_ITCR 0x300 /* VIC test control register */ 5344430ec0SRob Herring 5444430ec0SRob Herring #define VIC_VECT_CNTL_ENABLE (1 << 5) 5544430ec0SRob Herring 5644430ec0SRob Herring #define VIC_PL192_VECT_ADDR 0xF00 5744430ec0SRob Herring 5844430ec0SRob Herring /** 5944430ec0SRob Herring * struct vic_device - VIC PM device 60e641b987SLinus Walleij * @parent_irq: The parent IRQ number of the VIC if cascaded, or 0. 6144430ec0SRob Herring * @irq: The IRQ number for the base of the VIC. 6244430ec0SRob Herring * @base: The register base for the VIC. 6344430ec0SRob Herring * @valid_sources: A bitmask of valid interrupts 6444430ec0SRob Herring * @resume_sources: A bitmask of interrupts for resume. 6544430ec0SRob Herring * @resume_irqs: The IRQs enabled for resume. 6644430ec0SRob Herring * @int_select: Save for VIC_INT_SELECT. 6744430ec0SRob Herring * @int_enable: Save for VIC_INT_ENABLE. 6844430ec0SRob Herring * @soft_int: Save for VIC_INT_SOFT. 6944430ec0SRob Herring * @protect: Save for VIC_PROTECT. 7044430ec0SRob Herring * @domain: The IRQ domain for the VIC. 7144430ec0SRob Herring */ 7244430ec0SRob Herring struct vic_device { 7344430ec0SRob Herring void __iomem *base; 7444430ec0SRob Herring int irq; 7544430ec0SRob Herring u32 valid_sources; 7644430ec0SRob Herring u32 resume_sources; 7744430ec0SRob Herring u32 resume_irqs; 7844430ec0SRob Herring u32 int_select; 7944430ec0SRob Herring u32 int_enable; 8044430ec0SRob Herring u32 soft_int; 8144430ec0SRob Herring u32 protect; 8244430ec0SRob Herring struct irq_domain *domain; 8344430ec0SRob Herring }; 8444430ec0SRob Herring 8544430ec0SRob Herring /* we cannot allocate memory when VICs are initially registered */ 8644430ec0SRob Herring static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; 8744430ec0SRob Herring 8844430ec0SRob Herring static int vic_id; 8944430ec0SRob Herring 9044430ec0SRob Herring static void vic_handle_irq(struct pt_regs *regs); 9144430ec0SRob Herring 9244430ec0SRob Herring /** 9344430ec0SRob Herring * vic_init2 - common initialisation code 9444430ec0SRob Herring * @base: Base of the VIC. 9544430ec0SRob Herring * 9644430ec0SRob Herring * Common initialisation code for registration 9744430ec0SRob Herring * and resume. 9844430ec0SRob Herring */ 9944430ec0SRob Herring static void vic_init2(void __iomem *base) 10044430ec0SRob Herring { 10144430ec0SRob Herring int i; 10244430ec0SRob Herring 10344430ec0SRob Herring for (i = 0; i < 16; i++) { 10444430ec0SRob Herring void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); 10544430ec0SRob Herring writel(VIC_VECT_CNTL_ENABLE | i, reg); 10644430ec0SRob Herring } 10744430ec0SRob Herring 10844430ec0SRob Herring writel(32, base + VIC_PL190_DEF_VECT_ADDR); 10944430ec0SRob Herring } 11044430ec0SRob Herring 11144430ec0SRob Herring #ifdef CONFIG_PM 11244430ec0SRob Herring static void resume_one_vic(struct vic_device *vic) 11344430ec0SRob Herring { 11444430ec0SRob Herring void __iomem *base = vic->base; 11544430ec0SRob Herring 11644430ec0SRob Herring printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base); 11744430ec0SRob Herring 11844430ec0SRob Herring /* re-initialise static settings */ 11944430ec0SRob Herring vic_init2(base); 12044430ec0SRob Herring 12144430ec0SRob Herring writel(vic->int_select, base + VIC_INT_SELECT); 12244430ec0SRob Herring writel(vic->protect, base + VIC_PROTECT); 12344430ec0SRob Herring 12444430ec0SRob Herring /* set the enabled ints and then clear the non-enabled */ 12544430ec0SRob Herring writel(vic->int_enable, base + VIC_INT_ENABLE); 12644430ec0SRob Herring writel(~vic->int_enable, base + VIC_INT_ENABLE_CLEAR); 12744430ec0SRob Herring 12844430ec0SRob Herring /* and the same for the soft-int register */ 12944430ec0SRob Herring 13044430ec0SRob Herring writel(vic->soft_int, base + VIC_INT_SOFT); 13144430ec0SRob Herring writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR); 13244430ec0SRob Herring } 13344430ec0SRob Herring 13444430ec0SRob Herring static void vic_resume(void) 13544430ec0SRob Herring { 13644430ec0SRob Herring int id; 13744430ec0SRob Herring 13844430ec0SRob Herring for (id = vic_id - 1; id >= 0; id--) 13944430ec0SRob Herring resume_one_vic(vic_devices + id); 14044430ec0SRob Herring } 14144430ec0SRob Herring 14244430ec0SRob Herring static void suspend_one_vic(struct vic_device *vic) 14344430ec0SRob Herring { 14444430ec0SRob Herring void __iomem *base = vic->base; 14544430ec0SRob Herring 14644430ec0SRob Herring printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base); 14744430ec0SRob Herring 14844430ec0SRob Herring vic->int_select = readl(base + VIC_INT_SELECT); 14944430ec0SRob Herring vic->int_enable = readl(base + VIC_INT_ENABLE); 15044430ec0SRob Herring vic->soft_int = readl(base + VIC_INT_SOFT); 15144430ec0SRob Herring vic->protect = readl(base + VIC_PROTECT); 15244430ec0SRob Herring 15344430ec0SRob Herring /* set the interrupts (if any) that are used for 15444430ec0SRob Herring * resuming the system */ 15544430ec0SRob Herring 15644430ec0SRob Herring writel(vic->resume_irqs, base + VIC_INT_ENABLE); 15744430ec0SRob Herring writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR); 15844430ec0SRob Herring } 15944430ec0SRob Herring 16044430ec0SRob Herring static int vic_suspend(void) 16144430ec0SRob Herring { 16244430ec0SRob Herring int id; 16344430ec0SRob Herring 16444430ec0SRob Herring for (id = 0; id < vic_id; id++) 16544430ec0SRob Herring suspend_one_vic(vic_devices + id); 16644430ec0SRob Herring 16744430ec0SRob Herring return 0; 16844430ec0SRob Herring } 16944430ec0SRob Herring 17044430ec0SRob Herring struct syscore_ops vic_syscore_ops = { 17144430ec0SRob Herring .suspend = vic_suspend, 17244430ec0SRob Herring .resume = vic_resume, 17344430ec0SRob Herring }; 17444430ec0SRob Herring 17544430ec0SRob Herring /** 17644430ec0SRob Herring * vic_pm_init - initicall to register VIC pm 17744430ec0SRob Herring * 17844430ec0SRob Herring * This is called via late_initcall() to register 17944430ec0SRob Herring * the resources for the VICs due to the early 18044430ec0SRob Herring * nature of the VIC's registration. 18144430ec0SRob Herring */ 18244430ec0SRob Herring static int __init vic_pm_init(void) 18344430ec0SRob Herring { 18444430ec0SRob Herring if (vic_id > 0) 18544430ec0SRob Herring register_syscore_ops(&vic_syscore_ops); 18644430ec0SRob Herring 18744430ec0SRob Herring return 0; 18844430ec0SRob Herring } 18944430ec0SRob Herring late_initcall(vic_pm_init); 19044430ec0SRob Herring #endif /* CONFIG_PM */ 19144430ec0SRob Herring 19244430ec0SRob Herring static struct irq_chip vic_chip; 19344430ec0SRob Herring 19444430ec0SRob Herring static int vic_irqdomain_map(struct irq_domain *d, unsigned int irq, 19544430ec0SRob Herring irq_hw_number_t hwirq) 19644430ec0SRob Herring { 19744430ec0SRob Herring struct vic_device *v = d->host_data; 19844430ec0SRob Herring 19944430ec0SRob Herring /* Skip invalid IRQs, only register handlers for the real ones */ 20044430ec0SRob Herring if (!(v->valid_sources & (1 << hwirq))) 201d94ea3f6SGrant Likely return -EPERM; 20244430ec0SRob Herring irq_set_chip_and_handler(irq, &vic_chip, handle_level_irq); 20344430ec0SRob Herring irq_set_chip_data(irq, v->base); 20444430ec0SRob Herring set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 20544430ec0SRob Herring return 0; 20644430ec0SRob Herring } 20744430ec0SRob Herring 20844430ec0SRob Herring /* 20944430ec0SRob Herring * Handle each interrupt in a single VIC. Returns non-zero if we've 21044430ec0SRob Herring * handled at least one interrupt. This reads the status register 21144430ec0SRob Herring * before handling each interrupt, which is necessary given that 21244430ec0SRob Herring * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. 21344430ec0SRob Herring */ 21444430ec0SRob Herring static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) 21544430ec0SRob Herring { 21644430ec0SRob Herring u32 stat, irq; 21744430ec0SRob Herring int handled = 0; 21844430ec0SRob Herring 21944430ec0SRob Herring while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { 22044430ec0SRob Herring irq = ffs(stat) - 1; 22144430ec0SRob Herring handle_IRQ(irq_find_mapping(vic->domain, irq), regs); 22244430ec0SRob Herring handled = 1; 22344430ec0SRob Herring } 22444430ec0SRob Herring 22544430ec0SRob Herring return handled; 22644430ec0SRob Herring } 22744430ec0SRob Herring 228e641b987SLinus Walleij static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc) 229e641b987SLinus Walleij { 230e641b987SLinus Walleij u32 stat, hwirq; 231e641b987SLinus Walleij struct vic_device *vic = irq_desc_get_handler_data(desc); 232e641b987SLinus Walleij 233e641b987SLinus Walleij while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { 234e641b987SLinus Walleij hwirq = ffs(stat) - 1; 235e641b987SLinus Walleij generic_handle_irq(irq_find_mapping(vic->domain, hwirq)); 236e641b987SLinus Walleij } 237e641b987SLinus Walleij } 238e641b987SLinus Walleij 23944430ec0SRob Herring /* 24044430ec0SRob Herring * Keep iterating over all registered VIC's until there are no pending 24144430ec0SRob Herring * interrupts. 24244430ec0SRob Herring */ 24344430ec0SRob Herring static asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) 24444430ec0SRob Herring { 24544430ec0SRob Herring int i, handled; 24644430ec0SRob Herring 24744430ec0SRob Herring do { 24844430ec0SRob Herring for (i = 0, handled = 0; i < vic_id; ++i) 24944430ec0SRob Herring handled |= handle_one_vic(&vic_devices[i], regs); 25044430ec0SRob Herring } while (handled); 25144430ec0SRob Herring } 25244430ec0SRob Herring 25344430ec0SRob Herring static struct irq_domain_ops vic_irqdomain_ops = { 25444430ec0SRob Herring .map = vic_irqdomain_map, 25544430ec0SRob Herring .xlate = irq_domain_xlate_onetwocell, 25644430ec0SRob Herring }; 25744430ec0SRob Herring 25844430ec0SRob Herring /** 25944430ec0SRob Herring * vic_register() - Register a VIC. 26044430ec0SRob Herring * @base: The base address of the VIC. 261e641b987SLinus Walleij * @parent_irq: The parent IRQ if cascaded, else 0. 26244430ec0SRob Herring * @irq: The base IRQ for the VIC. 26344430ec0SRob Herring * @valid_sources: bitmask of valid interrupts 26444430ec0SRob Herring * @resume_sources: bitmask of interrupts allowed for resume sources. 26544430ec0SRob Herring * @node: The device tree node associated with the VIC. 26644430ec0SRob Herring * 26744430ec0SRob Herring * Register the VIC with the system device tree so that it can be notified 26844430ec0SRob Herring * of suspend and resume requests and ensure that the correct actions are 26944430ec0SRob Herring * taken to re-instate the settings on resume. 27044430ec0SRob Herring * 27144430ec0SRob Herring * This also configures the IRQ domain for the VIC. 27244430ec0SRob Herring */ 273e641b987SLinus Walleij static void __init vic_register(void __iomem *base, unsigned int parent_irq, 274e641b987SLinus Walleij unsigned int irq, 27544430ec0SRob Herring u32 valid_sources, u32 resume_sources, 27644430ec0SRob Herring struct device_node *node) 27744430ec0SRob Herring { 27844430ec0SRob Herring struct vic_device *v; 27944430ec0SRob Herring int i; 28044430ec0SRob Herring 28144430ec0SRob Herring if (vic_id >= ARRAY_SIZE(vic_devices)) { 28244430ec0SRob Herring printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); 28344430ec0SRob Herring return; 28444430ec0SRob Herring } 28544430ec0SRob Herring 28644430ec0SRob Herring v = &vic_devices[vic_id]; 28744430ec0SRob Herring v->base = base; 28844430ec0SRob Herring v->valid_sources = valid_sources; 28944430ec0SRob Herring v->resume_sources = resume_sources; 29044430ec0SRob Herring set_handle_irq(vic_handle_irq); 29144430ec0SRob Herring vic_id++; 292e641b987SLinus Walleij 293e641b987SLinus Walleij if (parent_irq) { 294e641b987SLinus Walleij irq_set_handler_data(parent_irq, v); 295e641b987SLinus Walleij irq_set_chained_handler(parent_irq, vic_handle_irq_cascaded); 296e641b987SLinus Walleij } 297e641b987SLinus Walleij 29844430ec0SRob Herring v->domain = irq_domain_add_simple(node, fls(valid_sources), irq, 29944430ec0SRob Herring &vic_irqdomain_ops, v); 30044430ec0SRob Herring /* create an IRQ mapping for each valid IRQ */ 30144430ec0SRob Herring for (i = 0; i < fls(valid_sources); i++) 30244430ec0SRob Herring if (valid_sources & (1 << i)) 30344430ec0SRob Herring irq_create_mapping(v->domain, i); 3043b4df9dbSLinus Walleij /* If no base IRQ was passed, figure out our allocated base */ 3053b4df9dbSLinus Walleij if (irq) 3063b4df9dbSLinus Walleij v->irq = irq; 3073b4df9dbSLinus Walleij else 3083b4df9dbSLinus Walleij v->irq = irq_find_mapping(v->domain, 0); 30944430ec0SRob Herring } 31044430ec0SRob Herring 31144430ec0SRob Herring static void vic_ack_irq(struct irq_data *d) 31244430ec0SRob Herring { 31344430ec0SRob Herring void __iomem *base = irq_data_get_irq_chip_data(d); 31444430ec0SRob Herring unsigned int irq = d->hwirq; 31544430ec0SRob Herring writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); 31644430ec0SRob Herring /* moreover, clear the soft-triggered, in case it was the reason */ 31744430ec0SRob Herring writel(1 << irq, base + VIC_INT_SOFT_CLEAR); 31844430ec0SRob Herring } 31944430ec0SRob Herring 32044430ec0SRob Herring static void vic_mask_irq(struct irq_data *d) 32144430ec0SRob Herring { 32244430ec0SRob Herring void __iomem *base = irq_data_get_irq_chip_data(d); 32344430ec0SRob Herring unsigned int irq = d->hwirq; 32444430ec0SRob Herring writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); 32544430ec0SRob Herring } 32644430ec0SRob Herring 32744430ec0SRob Herring static void vic_unmask_irq(struct irq_data *d) 32844430ec0SRob Herring { 32944430ec0SRob Herring void __iomem *base = irq_data_get_irq_chip_data(d); 33044430ec0SRob Herring unsigned int irq = d->hwirq; 33144430ec0SRob Herring writel(1 << irq, base + VIC_INT_ENABLE); 33244430ec0SRob Herring } 33344430ec0SRob Herring 33444430ec0SRob Herring #if defined(CONFIG_PM) 33544430ec0SRob Herring static struct vic_device *vic_from_irq(unsigned int irq) 33644430ec0SRob Herring { 33744430ec0SRob Herring struct vic_device *v = vic_devices; 33844430ec0SRob Herring unsigned int base_irq = irq & ~31; 33944430ec0SRob Herring int id; 34044430ec0SRob Herring 34144430ec0SRob Herring for (id = 0; id < vic_id; id++, v++) { 34244430ec0SRob Herring if (v->irq == base_irq) 34344430ec0SRob Herring return v; 34444430ec0SRob Herring } 34544430ec0SRob Herring 34644430ec0SRob Herring return NULL; 34744430ec0SRob Herring } 34844430ec0SRob Herring 34944430ec0SRob Herring static int vic_set_wake(struct irq_data *d, unsigned int on) 35044430ec0SRob Herring { 35144430ec0SRob Herring struct vic_device *v = vic_from_irq(d->irq); 35244430ec0SRob Herring unsigned int off = d->hwirq; 35344430ec0SRob Herring u32 bit = 1 << off; 35444430ec0SRob Herring 35544430ec0SRob Herring if (!v) 35644430ec0SRob Herring return -EINVAL; 35744430ec0SRob Herring 35844430ec0SRob Herring if (!(bit & v->resume_sources)) 35944430ec0SRob Herring return -EINVAL; 36044430ec0SRob Herring 36144430ec0SRob Herring if (on) 36244430ec0SRob Herring v->resume_irqs |= bit; 36344430ec0SRob Herring else 36444430ec0SRob Herring v->resume_irqs &= ~bit; 36544430ec0SRob Herring 36644430ec0SRob Herring return 0; 36744430ec0SRob Herring } 36844430ec0SRob Herring #else 36944430ec0SRob Herring #define vic_set_wake NULL 37044430ec0SRob Herring #endif /* CONFIG_PM */ 37144430ec0SRob Herring 37244430ec0SRob Herring static struct irq_chip vic_chip = { 37344430ec0SRob Herring .name = "VIC", 37444430ec0SRob Herring .irq_ack = vic_ack_irq, 37544430ec0SRob Herring .irq_mask = vic_mask_irq, 37644430ec0SRob Herring .irq_unmask = vic_unmask_irq, 37744430ec0SRob Herring .irq_set_wake = vic_set_wake, 37844430ec0SRob Herring }; 37944430ec0SRob Herring 38044430ec0SRob Herring static void __init vic_disable(void __iomem *base) 38144430ec0SRob Herring { 38244430ec0SRob Herring writel(0, base + VIC_INT_SELECT); 38344430ec0SRob Herring writel(0, base + VIC_INT_ENABLE); 38444430ec0SRob Herring writel(~0, base + VIC_INT_ENABLE_CLEAR); 38544430ec0SRob Herring writel(0, base + VIC_ITCR); 38644430ec0SRob Herring writel(~0, base + VIC_INT_SOFT_CLEAR); 38744430ec0SRob Herring } 38844430ec0SRob Herring 38944430ec0SRob Herring static void __init vic_clear_interrupts(void __iomem *base) 39044430ec0SRob Herring { 39144430ec0SRob Herring unsigned int i; 39244430ec0SRob Herring 39344430ec0SRob Herring writel(0, base + VIC_PL190_VECT_ADDR); 39444430ec0SRob Herring for (i = 0; i < 19; i++) { 39544430ec0SRob Herring unsigned int value; 39644430ec0SRob Herring 39744430ec0SRob Herring value = readl(base + VIC_PL190_VECT_ADDR); 39844430ec0SRob Herring writel(value, base + VIC_PL190_VECT_ADDR); 39944430ec0SRob Herring } 40044430ec0SRob Herring } 40144430ec0SRob Herring 40244430ec0SRob Herring /* 40344430ec0SRob Herring * The PL190 cell from ARM has been modified by ST to handle 64 interrupts. 40444430ec0SRob Herring * The original cell has 32 interrupts, while the modified one has 64, 40544430ec0SRob Herring * replocating two blocks 0x00..0x1f in 0x20..0x3f. In that case 40644430ec0SRob Herring * the probe function is called twice, with base set to offset 000 40744430ec0SRob Herring * and 020 within the page. We call this "second block". 40844430ec0SRob Herring */ 40944430ec0SRob Herring static void __init vic_init_st(void __iomem *base, unsigned int irq_start, 41044430ec0SRob Herring u32 vic_sources, struct device_node *node) 41144430ec0SRob Herring { 41244430ec0SRob Herring unsigned int i; 41344430ec0SRob Herring int vic_2nd_block = ((unsigned long)base & ~PAGE_MASK) != 0; 41444430ec0SRob Herring 41544430ec0SRob Herring /* Disable all interrupts initially. */ 41644430ec0SRob Herring vic_disable(base); 41744430ec0SRob Herring 41844430ec0SRob Herring /* 41944430ec0SRob Herring * Make sure we clear all existing interrupts. The vector registers 42044430ec0SRob Herring * in this cell are after the second block of general registers, 42144430ec0SRob Herring * so we can address them using standard offsets, but only from 42244430ec0SRob Herring * the second base address, which is 0x20 in the page 42344430ec0SRob Herring */ 42444430ec0SRob Herring if (vic_2nd_block) { 42544430ec0SRob Herring vic_clear_interrupts(base); 42644430ec0SRob Herring 42744430ec0SRob Herring /* ST has 16 vectors as well, but we don't enable them by now */ 42844430ec0SRob Herring for (i = 0; i < 16; i++) { 42944430ec0SRob Herring void __iomem *reg = base + VIC_VECT_CNTL0 + (i * 4); 43044430ec0SRob Herring writel(0, reg); 43144430ec0SRob Herring } 43244430ec0SRob Herring 43344430ec0SRob Herring writel(32, base + VIC_PL190_DEF_VECT_ADDR); 43444430ec0SRob Herring } 43544430ec0SRob Herring 436e641b987SLinus Walleij vic_register(base, 0, irq_start, vic_sources, 0, node); 43744430ec0SRob Herring } 43844430ec0SRob Herring 439e641b987SLinus Walleij void __init __vic_init(void __iomem *base, int parent_irq, int irq_start, 44044430ec0SRob Herring u32 vic_sources, u32 resume_sources, 44144430ec0SRob Herring struct device_node *node) 44244430ec0SRob Herring { 44344430ec0SRob Herring unsigned int i; 44444430ec0SRob Herring u32 cellid = 0; 44544430ec0SRob Herring enum amba_vendor vendor; 44644430ec0SRob Herring 44744430ec0SRob Herring /* Identify which VIC cell this one is, by reading the ID */ 44844430ec0SRob Herring for (i = 0; i < 4; i++) { 44944430ec0SRob Herring void __iomem *addr; 45044430ec0SRob Herring addr = (void __iomem *)((u32)base & PAGE_MASK) + 0xfe0 + (i * 4); 45144430ec0SRob Herring cellid |= (readl(addr) & 0xff) << (8 * i); 45244430ec0SRob Herring } 45344430ec0SRob Herring vendor = (cellid >> 12) & 0xff; 45444430ec0SRob Herring printk(KERN_INFO "VIC @%p: id 0x%08x, vendor 0x%02x\n", 45544430ec0SRob Herring base, cellid, vendor); 45644430ec0SRob Herring 45744430ec0SRob Herring switch(vendor) { 45844430ec0SRob Herring case AMBA_VENDOR_ST: 45944430ec0SRob Herring vic_init_st(base, irq_start, vic_sources, node); 46044430ec0SRob Herring return; 46144430ec0SRob Herring default: 46244430ec0SRob Herring printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n"); 46344430ec0SRob Herring /* fall through */ 46444430ec0SRob Herring case AMBA_VENDOR_ARM: 46544430ec0SRob Herring break; 46644430ec0SRob Herring } 46744430ec0SRob Herring 46844430ec0SRob Herring /* Disable all interrupts initially. */ 46944430ec0SRob Herring vic_disable(base); 47044430ec0SRob Herring 47144430ec0SRob Herring /* Make sure we clear all existing interrupts */ 47244430ec0SRob Herring vic_clear_interrupts(base); 47344430ec0SRob Herring 47444430ec0SRob Herring vic_init2(base); 47544430ec0SRob Herring 476e641b987SLinus Walleij vic_register(base, parent_irq, irq_start, vic_sources, resume_sources, node); 47744430ec0SRob Herring } 47844430ec0SRob Herring 47944430ec0SRob Herring /** 48044430ec0SRob Herring * vic_init() - initialise a vectored interrupt controller 48144430ec0SRob Herring * @base: iomem base address 48244430ec0SRob Herring * @irq_start: starting interrupt number, must be muliple of 32 48344430ec0SRob Herring * @vic_sources: bitmask of interrupt sources to allow 48444430ec0SRob Herring * @resume_sources: bitmask of interrupt sources to allow for resume 48544430ec0SRob Herring */ 48644430ec0SRob Herring void __init vic_init(void __iomem *base, unsigned int irq_start, 48744430ec0SRob Herring u32 vic_sources, u32 resume_sources) 48844430ec0SRob Herring { 489e641b987SLinus Walleij __vic_init(base, 0, irq_start, vic_sources, resume_sources, NULL); 490e641b987SLinus Walleij } 491e641b987SLinus Walleij 492e641b987SLinus Walleij /** 493e641b987SLinus Walleij * vic_init_cascaded() - initialise a cascaded vectored interrupt controller 494e641b987SLinus Walleij * @base: iomem base address 495e641b987SLinus Walleij * @parent_irq: the parent IRQ we're cascaded off 496e641b987SLinus Walleij * @irq_start: starting interrupt number, must be muliple of 32 497e641b987SLinus Walleij * @vic_sources: bitmask of interrupt sources to allow 498e641b987SLinus Walleij * @resume_sources: bitmask of interrupt sources to allow for resume 499e641b987SLinus Walleij * 500e641b987SLinus Walleij * This returns the base for the new interrupts or negative on error. 501e641b987SLinus Walleij */ 502e641b987SLinus Walleij int __init vic_init_cascaded(void __iomem *base, unsigned int parent_irq, 503e641b987SLinus Walleij u32 vic_sources, u32 resume_sources) 504e641b987SLinus Walleij { 505e641b987SLinus Walleij struct vic_device *v; 506e641b987SLinus Walleij 507e641b987SLinus Walleij v = &vic_devices[vic_id]; 508e641b987SLinus Walleij __vic_init(base, parent_irq, 0, vic_sources, resume_sources, NULL); 509e641b987SLinus Walleij /* Return out acquired base */ 510e641b987SLinus Walleij return v->irq; 51144430ec0SRob Herring } 51244430ec0SRob Herring 51344430ec0SRob Herring #ifdef CONFIG_OF 51444430ec0SRob Herring int __init vic_of_init(struct device_node *node, struct device_node *parent) 51544430ec0SRob Herring { 51644430ec0SRob Herring void __iomem *regs; 51781e9c179STomasz Figa u32 interrupt_mask = ~0; 51881e9c179STomasz Figa u32 wakeup_mask = ~0; 51944430ec0SRob Herring 52044430ec0SRob Herring if (WARN(parent, "non-root VICs are not supported")) 52144430ec0SRob Herring return -EINVAL; 52244430ec0SRob Herring 52344430ec0SRob Herring regs = of_iomap(node, 0); 52444430ec0SRob Herring if (WARN_ON(!regs)) 52544430ec0SRob Herring return -EIO; 52644430ec0SRob Herring 52781e9c179STomasz Figa of_property_read_u32(node, "valid-mask", &interrupt_mask); 52881e9c179STomasz Figa of_property_read_u32(node, "valid-wakeup-mask", &wakeup_mask); 52981e9c179STomasz Figa 53044430ec0SRob Herring /* 53144430ec0SRob Herring * Passing 0 as first IRQ makes the simple domain allocate descriptors 53244430ec0SRob Herring */ 533e641b987SLinus Walleij __vic_init(regs, 0, 0, interrupt_mask, wakeup_mask, node); 53444430ec0SRob Herring 53544430ec0SRob Herring return 0; 53644430ec0SRob Herring } 53744430ec0SRob Herring IRQCHIP_DECLARE(arm_pl190_vic, "arm,pl190-vic", vic_of_init); 53844430ec0SRob Herring IRQCHIP_DECLARE(arm_pl192_vic, "arm,pl192-vic", vic_of_init); 53944430ec0SRob Herring IRQCHIP_DECLARE(arm_versatile_vic, "arm,versatile-vic", vic_of_init); 54044430ec0SRob Herring #endif /* CONFIG OF */ 541