Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.7 325 lines 9.2 kB view raw
1/* 2 * Root interrupt controller for the BCM2836 (Raspberry Pi 2). 3 * 4 * Copyright 2015 Broadcom 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/cpu.h> 18#include <linux/of_address.h> 19#include <linux/of_irq.h> 20#include <linux/irqchip.h> 21#include <linux/irqdomain.h> 22#include <asm/exception.h> 23 24#define LOCAL_CONTROL 0x000 25#define LOCAL_PRESCALER 0x008 26 27/* 28 * The low 2 bits identify the CPU that the GPU IRQ goes to, and the 29 * next 2 bits identify the CPU that the GPU FIQ goes to. 30 */ 31#define LOCAL_GPU_ROUTING 0x00c 32/* When setting bits 0-3, enables PMU interrupts on that CPU. */ 33#define LOCAL_PM_ROUTING_SET 0x010 34/* When setting bits 0-3, disables PMU interrupts on that CPU. */ 35#define LOCAL_PM_ROUTING_CLR 0x014 36/* 37 * The low 4 bits of this are the CPU's timer IRQ enables, and the 38 * next 4 bits are the CPU's timer FIQ enables (which override the IRQ 39 * bits). 40 */ 41#define LOCAL_TIMER_INT_CONTROL0 0x040 42/* 43 * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and 44 * the next 4 bits are the CPU's per-mailbox FIQ enables (which 45 * override the IRQ bits). 46 */ 47#define LOCAL_MAILBOX_INT_CONTROL0 0x050 48/* 49 * The CPU's interrupt status register. Bits are defined by the the 50 * LOCAL_IRQ_* bits below. 51 */ 52#define LOCAL_IRQ_PENDING0 0x060 53/* Same status bits as above, but for FIQ. */ 54#define LOCAL_FIQ_PENDING0 0x070 55/* 56 * Mailbox write-to-set bits. There are 16 mailboxes, 4 per CPU, and 57 * these bits are organized by mailbox number and then CPU number. We 58 * use mailbox 0 for IPIs. The mailbox's interrupt is raised while 59 * any bit is set. 60 */ 61#define LOCAL_MAILBOX0_SET0 0x080 62#define LOCAL_MAILBOX3_SET0 0x08c 63/* Mailbox write-to-clear bits. */ 64#define LOCAL_MAILBOX0_CLR0 0x0c0 65#define LOCAL_MAILBOX3_CLR0 0x0cc 66 67#define LOCAL_IRQ_CNTPSIRQ 0 68#define LOCAL_IRQ_CNTPNSIRQ 1 69#define LOCAL_IRQ_CNTHPIRQ 2 70#define LOCAL_IRQ_CNTVIRQ 3 71#define LOCAL_IRQ_MAILBOX0 4 72#define LOCAL_IRQ_MAILBOX1 5 73#define LOCAL_IRQ_MAILBOX2 6 74#define LOCAL_IRQ_MAILBOX3 7 75#define LOCAL_IRQ_GPU_FAST 8 76#define LOCAL_IRQ_PMU_FAST 9 77#define LAST_IRQ LOCAL_IRQ_PMU_FAST 78 79struct bcm2836_arm_irqchip_intc { 80 struct irq_domain *domain; 81 void __iomem *base; 82}; 83 84static struct bcm2836_arm_irqchip_intc intc __read_mostly; 85 86static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, 87 unsigned int bit, 88 int cpu) 89{ 90 void __iomem *reg = intc.base + reg_offset + 4 * cpu; 91 92 writel(readl(reg) & ~BIT(bit), reg); 93} 94 95static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset, 96 unsigned int bit, 97 int cpu) 98{ 99 void __iomem *reg = intc.base + reg_offset + 4 * cpu; 100 101 writel(readl(reg) | BIT(bit), reg); 102} 103 104static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d) 105{ 106 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, 107 d->hwirq - LOCAL_IRQ_CNTPSIRQ, 108 smp_processor_id()); 109} 110 111static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d) 112{ 113 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, 114 d->hwirq - LOCAL_IRQ_CNTPSIRQ, 115 smp_processor_id()); 116} 117 118static struct irq_chip bcm2836_arm_irqchip_timer = { 119 .name = "bcm2836-timer", 120 .irq_mask = bcm2836_arm_irqchip_mask_timer_irq, 121 .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq, 122}; 123 124static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d) 125{ 126 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR); 127} 128 129static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d) 130{ 131 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET); 132} 133 134static struct irq_chip bcm2836_arm_irqchip_pmu = { 135 .name = "bcm2836-pmu", 136 .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq, 137 .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq, 138}; 139 140static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d) 141{ 142} 143 144static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) 145{ 146} 147 148static struct irq_chip bcm2836_arm_irqchip_gpu = { 149 .name = "bcm2836-gpu", 150 .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, 151 .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, 152}; 153 154static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) 155{ 156 int irq = irq_create_mapping(intc.domain, hwirq); 157 158 irq_set_percpu_devid(irq); 159 irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); 160 irq_set_status_flags(irq, IRQ_NOAUTOEN); 161} 162 163static void 164__exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) 165{ 166 int cpu = smp_processor_id(); 167 u32 stat; 168 169 stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); 170 if (stat & BIT(LOCAL_IRQ_MAILBOX0)) { 171#ifdef CONFIG_SMP 172 void __iomem *mailbox0 = (intc.base + 173 LOCAL_MAILBOX0_CLR0 + 16 * cpu); 174 u32 mbox_val = readl(mailbox0); 175 u32 ipi = ffs(mbox_val) - 1; 176 177 writel(1 << ipi, mailbox0); 178 handle_IPI(ipi, regs); 179#endif 180 } else if (stat) { 181 u32 hwirq = ffs(stat) - 1; 182 183 handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); 184 } 185} 186 187#ifdef CONFIG_SMP 188static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, 189 unsigned int ipi) 190{ 191 int cpu; 192 void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; 193 194 /* 195 * Ensure that stores to normal memory are visible to the 196 * other CPUs before issuing the IPI. 197 */ 198 smp_wmb(); 199 200 for_each_cpu(cpu, mask) { 201 writel(1 << ipi, mailbox0_base + 16 * cpu); 202 } 203} 204 205/* Unmasks the IPI on the CPU when it's online. */ 206static int bcm2836_arm_irqchip_cpu_notify(struct notifier_block *nfb, 207 unsigned long action, void *hcpu) 208{ 209 unsigned int cpu = (unsigned long)hcpu; 210 unsigned int int_reg = LOCAL_MAILBOX_INT_CONTROL0; 211 unsigned int mailbox = 0; 212 213 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) 214 bcm2836_arm_irqchip_unmask_per_cpu_irq(int_reg, mailbox, cpu); 215 else if (action == CPU_DYING) 216 bcm2836_arm_irqchip_mask_per_cpu_irq(int_reg, mailbox, cpu); 217 218 return NOTIFY_OK; 219} 220 221static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = { 222 .notifier_call = bcm2836_arm_irqchip_cpu_notify, 223 .priority = 100, 224}; 225 226#ifdef CONFIG_ARM 227int __init bcm2836_smp_boot_secondary(unsigned int cpu, 228 struct task_struct *idle) 229{ 230 unsigned long secondary_startup_phys = 231 (unsigned long)virt_to_phys((void *)secondary_startup); 232 233 writel(secondary_startup_phys, 234 intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu); 235 236 return 0; 237} 238 239static const struct smp_operations bcm2836_smp_ops __initconst = { 240 .smp_boot_secondary = bcm2836_smp_boot_secondary, 241}; 242#endif 243#endif 244 245static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { 246 .xlate = irq_domain_xlate_onecell 247}; 248 249static void 250bcm2836_arm_irqchip_smp_init(void) 251{ 252#ifdef CONFIG_SMP 253 /* Unmask IPIs to the boot CPU. */ 254 bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier, 255 CPU_STARTING, 256 (void *)(uintptr_t)smp_processor_id()); 257 register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier); 258 259 set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); 260 261#ifdef CONFIG_ARM 262 smp_set_ops(&bcm2836_smp_ops); 263#endif 264#endif 265} 266 267/* 268 * The LOCAL_IRQ_CNT* timer firings are based off of the external 269 * oscillator with some scaling. The firmware sets up CNTFRQ to 270 * report 19.2Mhz, but doesn't set up the scaling registers. 271 */ 272static void bcm2835_init_local_timer_frequency(void) 273{ 274 /* 275 * Set the timer to source from the 19.2Mhz crystal clock (bit 276 * 8 unset), and only increment by 1 instead of 2 (bit 9 277 * unset). 278 */ 279 writel(0, intc.base + LOCAL_CONTROL); 280 281 /* 282 * Set the timer prescaler to 1:1 (timer freq = input freq * 283 * 2**31 / prescaler) 284 */ 285 writel(0x80000000, intc.base + LOCAL_PRESCALER); 286} 287 288static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, 289 struct device_node *parent) 290{ 291 intc.base = of_iomap(node, 0); 292 if (!intc.base) { 293 panic("%s: unable to map local interrupt registers\n", 294 node->full_name); 295 } 296 297 bcm2835_init_local_timer_frequency(); 298 299 intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1, 300 &bcm2836_arm_irqchip_intc_ops, 301 NULL); 302 if (!intc.domain) 303 panic("%s: unable to create IRQ domain\n", node->full_name); 304 305 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ, 306 &bcm2836_arm_irqchip_timer); 307 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ, 308 &bcm2836_arm_irqchip_timer); 309 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ, 310 &bcm2836_arm_irqchip_timer); 311 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ, 312 &bcm2836_arm_irqchip_timer); 313 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST, 314 &bcm2836_arm_irqchip_gpu); 315 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST, 316 &bcm2836_arm_irqchip_pmu); 317 318 bcm2836_arm_irqchip_smp_init(); 319 320 set_handle_irq(bcm2836_arm_irqchip_handle_irq); 321 return 0; 322} 323 324IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc", 325 bcm2836_arm_irqchip_l1_intc_of_init);