1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Root interrupt controller for the BCM2836 (Raspberry Pi 2). 4 * 5 * Copyright 2015 Broadcom 6 */ 7 8 #include <linux/cpu.h> 9 #include <linux/of_address.h> 10 #include <linux/of_irq.h> 11 #include <linux/irqchip.h> 12 #include <linux/irqdomain.h> 13 #include <linux/irqchip/irq-bcm2836.h> 14 15 #include <asm/exception.h> 16 17 struct bcm2836_arm_irqchip_intc { 18 struct irq_domain *domain; 19 void __iomem *base; 20 }; 21 22 static struct bcm2836_arm_irqchip_intc intc __read_mostly; 23 24 static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, 25 unsigned int bit, 26 int cpu) 27 { 28 void __iomem *reg = intc.base + reg_offset + 4 * cpu; 29 30 writel(readl(reg) & ~BIT(bit), reg); 31 } 32 33 static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset, 34 unsigned int bit, 35 int cpu) 36 { 37 void __iomem *reg = intc.base + reg_offset + 4 * cpu; 38 39 writel(readl(reg) | BIT(bit), reg); 40 } 41 42 static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d) 43 { 44 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, 45 d->hwirq - LOCAL_IRQ_CNTPSIRQ, 46 smp_processor_id()); 47 } 48 49 static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d) 50 { 51 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, 52 d->hwirq - LOCAL_IRQ_CNTPSIRQ, 53 smp_processor_id()); 54 } 55 56 static struct irq_chip bcm2836_arm_irqchip_timer = { 57 .name = "bcm2836-timer", 58 .irq_mask = bcm2836_arm_irqchip_mask_timer_irq, 59 .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq, 60 }; 61 62 static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d) 63 { 64 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR); 65 } 66 67 static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d) 68 { 69 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET); 70 } 71 72 static struct irq_chip bcm2836_arm_irqchip_pmu = { 73 .name = "bcm2836-pmu", 74 .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq, 75 .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq, 76 }; 77 78 static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d) 79 { 80 } 81 82 static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) 83 { 84 } 85 86 static struct irq_chip bcm2836_arm_irqchip_gpu = { 87 .name = "bcm2836-gpu", 88 .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, 89 .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, 90 }; 91 92 static int bcm2836_map(struct irq_domain *d, unsigned int irq, 93 irq_hw_number_t hw) 94 { 95 struct irq_chip *chip; 96 97 switch (hw) { 98 case LOCAL_IRQ_CNTPSIRQ: 99 case LOCAL_IRQ_CNTPNSIRQ: 100 case LOCAL_IRQ_CNTHPIRQ: 101 case LOCAL_IRQ_CNTVIRQ: 102 chip = &bcm2836_arm_irqchip_timer; 103 break; 104 case LOCAL_IRQ_GPU_FAST: 105 chip = &bcm2836_arm_irqchip_gpu; 106 break; 107 case LOCAL_IRQ_PMU_FAST: 108 chip = &bcm2836_arm_irqchip_pmu; 109 break; 110 default: 111 pr_warn_once("Unexpected hw irq: %lu\n", hw); 112 return -EINVAL; 113 } 114 115 irq_set_percpu_devid(irq); 116 irq_domain_set_info(d, irq, hw, chip, d->host_data, 117 handle_percpu_devid_irq, NULL, NULL); 118 irq_set_status_flags(irq, IRQ_NOAUTOEN); 119 120 return 0; 121 } 122 123 static void 124 __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) 125 { 126 int cpu = smp_processor_id(); 127 u32 stat; 128 129 stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu); 130 if (stat & BIT(LOCAL_IRQ_MAILBOX0)) { 131 #ifdef CONFIG_SMP 132 void __iomem *mailbox0 = (intc.base + 133 LOCAL_MAILBOX0_CLR0 + 16 * cpu); 134 u32 mbox_val = readl(mailbox0); 135 u32 ipi = ffs(mbox_val) - 1; 136 137 writel(1 << ipi, mailbox0); 138 handle_IPI(ipi, regs); 139 #endif 140 } else if (stat) { 141 u32 hwirq = ffs(stat) - 1; 142 143 handle_domain_irq(intc.domain, hwirq, regs); 144 } 145 } 146 147 #ifdef CONFIG_SMP 148 static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask, 149 unsigned int ipi) 150 { 151 int cpu; 152 void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0; 153 154 /* 155 * Ensure that stores to normal memory are visible to the 156 * other CPUs before issuing the IPI. 157 */ 158 smp_wmb(); 159 160 for_each_cpu(cpu, mask) { 161 writel(1 << ipi, mailbox0_base + 16 * cpu); 162 } 163 } 164 165 static int bcm2836_cpu_starting(unsigned int cpu) 166 { 167 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0, 168 cpu); 169 return 0; 170 } 171 172 static int bcm2836_cpu_dying(unsigned int cpu) 173 { 174 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0, 175 cpu); 176 return 0; 177 } 178 #endif 179 180 static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = { 181 .xlate = irq_domain_xlate_onetwocell, 182 .map = bcm2836_map, 183 }; 184 185 static void 186 bcm2836_arm_irqchip_smp_init(void) 187 { 188 #ifdef CONFIG_SMP 189 /* Unmask IPIs to the boot CPU. */ 190 cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING, 191 "irqchip/bcm2836:starting", bcm2836_cpu_starting, 192 bcm2836_cpu_dying); 193 194 set_smp_cross_call(bcm2836_arm_irqchip_send_ipi); 195 #endif 196 } 197 198 /* 199 * The LOCAL_IRQ_CNT* timer firings are based off of the external 200 * oscillator with some scaling. The firmware sets up CNTFRQ to 201 * report 19.2Mhz, but doesn't set up the scaling registers. 202 */ 203 static void bcm2835_init_local_timer_frequency(void) 204 { 205 /* 206 * Set the timer to source from the 19.2Mhz crystal clock (bit 207 * 8 unset), and only increment by 1 instead of 2 (bit 9 208 * unset). 209 */ 210 writel(0, intc.base + LOCAL_CONTROL); 211 212 /* 213 * Set the timer prescaler to 1:1 (timer freq = input freq * 214 * 2**31 / prescaler) 215 */ 216 writel(0x80000000, intc.base + LOCAL_PRESCALER); 217 } 218 219 static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, 220 struct device_node *parent) 221 { 222 intc.base = of_iomap(node, 0); 223 if (!intc.base) { 224 panic("%pOF: unable to map local interrupt registers\n", node); 225 } 226 227 bcm2835_init_local_timer_frequency(); 228 229 intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1, 230 &bcm2836_arm_irqchip_intc_ops, 231 NULL); 232 if (!intc.domain) 233 panic("%pOF: unable to create IRQ domain\n", node); 234 235 bcm2836_arm_irqchip_smp_init(); 236 237 set_handle_irq(bcm2836_arm_irqchip_handle_irq); 238 return 0; 239 } 240 241 IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc", 242 bcm2836_arm_irqchip_l1_intc_of_init); 243