0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/cpu.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_irq.h>
0011 #include <linux/irqchip.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/irqchip/chained_irq.h>
0014 #include <linux/irqchip/irq-bcm2836.h>
0015
0016 #include <asm/exception.h>
0017
0018 struct bcm2836_arm_irqchip_intc {
0019 struct irq_domain *domain;
0020 void __iomem *base;
0021 };
0022
0023 static struct bcm2836_arm_irqchip_intc intc __read_mostly;
0024
0025 static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
0026 unsigned int bit,
0027 int cpu)
0028 {
0029 void __iomem *reg = intc.base + reg_offset + 4 * cpu;
0030
0031 writel(readl(reg) & ~BIT(bit), reg);
0032 }
0033
0034 static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset,
0035 unsigned int bit,
0036 int cpu)
0037 {
0038 void __iomem *reg = intc.base + reg_offset + 4 * cpu;
0039
0040 writel(readl(reg) | BIT(bit), reg);
0041 }
0042
0043 static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d)
0044 {
0045 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
0046 d->hwirq - LOCAL_IRQ_CNTPSIRQ,
0047 smp_processor_id());
0048 }
0049
0050 static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d)
0051 {
0052 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
0053 d->hwirq - LOCAL_IRQ_CNTPSIRQ,
0054 smp_processor_id());
0055 }
0056
0057 static struct irq_chip bcm2836_arm_irqchip_timer = {
0058 .name = "bcm2836-timer",
0059 .irq_mask = bcm2836_arm_irqchip_mask_timer_irq,
0060 .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq,
0061 };
0062
0063 static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d)
0064 {
0065 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR);
0066 }
0067
0068 static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d)
0069 {
0070 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET);
0071 }
0072
0073 static struct irq_chip bcm2836_arm_irqchip_pmu = {
0074 .name = "bcm2836-pmu",
0075 .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq,
0076 .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq,
0077 };
0078
0079 static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d)
0080 {
0081 }
0082
0083 static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d)
0084 {
0085 }
0086
0087 static struct irq_chip bcm2836_arm_irqchip_gpu = {
0088 .name = "bcm2836-gpu",
0089 .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,
0090 .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
0091 };
0092
0093 static void bcm2836_arm_irqchip_dummy_op(struct irq_data *d)
0094 {
0095 }
0096
0097 static struct irq_chip bcm2836_arm_irqchip_dummy = {
0098 .name = "bcm2836-dummy",
0099 .irq_eoi = bcm2836_arm_irqchip_dummy_op,
0100 };
0101
0102 static int bcm2836_map(struct irq_domain *d, unsigned int irq,
0103 irq_hw_number_t hw)
0104 {
0105 struct irq_chip *chip;
0106
0107 switch (hw) {
0108 case LOCAL_IRQ_MAILBOX0:
0109 chip = &bcm2836_arm_irqchip_dummy;
0110 break;
0111 case LOCAL_IRQ_CNTPSIRQ:
0112 case LOCAL_IRQ_CNTPNSIRQ:
0113 case LOCAL_IRQ_CNTHPIRQ:
0114 case LOCAL_IRQ_CNTVIRQ:
0115 chip = &bcm2836_arm_irqchip_timer;
0116 break;
0117 case LOCAL_IRQ_GPU_FAST:
0118 chip = &bcm2836_arm_irqchip_gpu;
0119 break;
0120 case LOCAL_IRQ_PMU_FAST:
0121 chip = &bcm2836_arm_irqchip_pmu;
0122 break;
0123 default:
0124 pr_warn_once("Unexpected hw irq: %lu\n", hw);
0125 return -EINVAL;
0126 }
0127
0128 irq_set_percpu_devid(irq);
0129 irq_domain_set_info(d, irq, hw, chip, d->host_data,
0130 handle_percpu_devid_irq, NULL, NULL);
0131 irq_set_status_flags(irq, IRQ_NOAUTOEN);
0132
0133 return 0;
0134 }
0135
0136 static void
0137 __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
0138 {
0139 int cpu = smp_processor_id();
0140 u32 stat;
0141
0142 stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
0143 if (stat) {
0144 u32 hwirq = ffs(stat) - 1;
0145
0146 generic_handle_domain_irq(intc.domain, hwirq);
0147 }
0148 }
0149
0150 #ifdef CONFIG_SMP
0151 static struct irq_domain *ipi_domain;
0152
0153 static void bcm2836_arm_irqchip_handle_ipi(struct irq_desc *desc)
0154 {
0155 struct irq_chip *chip = irq_desc_get_chip(desc);
0156 int cpu = smp_processor_id();
0157 u32 mbox_val;
0158
0159 chained_irq_enter(chip, desc);
0160
0161 mbox_val = readl_relaxed(intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
0162 if (mbox_val) {
0163 int hwirq = ffs(mbox_val) - 1;
0164 generic_handle_domain_irq(ipi_domain, hwirq);
0165 }
0166
0167 chained_irq_exit(chip, desc);
0168 }
0169
0170 static void bcm2836_arm_irqchip_ipi_ack(struct irq_data *d)
0171 {
0172 int cpu = smp_processor_id();
0173
0174 writel_relaxed(BIT(d->hwirq),
0175 intc.base + LOCAL_MAILBOX0_CLR0 + 16 * cpu);
0176 }
0177
0178 static void bcm2836_arm_irqchip_ipi_send_mask(struct irq_data *d,
0179 const struct cpumask *mask)
0180 {
0181 int cpu;
0182 void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0;
0183
0184
0185
0186
0187
0188 smp_wmb();
0189
0190 for_each_cpu(cpu, mask)
0191 writel_relaxed(BIT(d->hwirq), mailbox0_base + 16 * cpu);
0192 }
0193
0194 static struct irq_chip bcm2836_arm_irqchip_ipi = {
0195 .name = "IPI",
0196 .irq_mask = bcm2836_arm_irqchip_dummy_op,
0197 .irq_unmask = bcm2836_arm_irqchip_dummy_op,
0198 .irq_ack = bcm2836_arm_irqchip_ipi_ack,
0199 .ipi_send_mask = bcm2836_arm_irqchip_ipi_send_mask,
0200 };
0201
0202 static int bcm2836_arm_irqchip_ipi_alloc(struct irq_domain *d,
0203 unsigned int virq,
0204 unsigned int nr_irqs, void *args)
0205 {
0206 int i;
0207
0208 for (i = 0; i < nr_irqs; i++) {
0209 irq_set_percpu_devid(virq + i);
0210 irq_domain_set_info(d, virq + i, i, &bcm2836_arm_irqchip_ipi,
0211 d->host_data,
0212 handle_percpu_devid_irq,
0213 NULL, NULL);
0214 }
0215
0216 return 0;
0217 }
0218
0219 static void bcm2836_arm_irqchip_ipi_free(struct irq_domain *d,
0220 unsigned int virq,
0221 unsigned int nr_irqs)
0222 {
0223
0224 }
0225
0226 static const struct irq_domain_ops ipi_domain_ops = {
0227 .alloc = bcm2836_arm_irqchip_ipi_alloc,
0228 .free = bcm2836_arm_irqchip_ipi_free,
0229 };
0230
0231 static int bcm2836_cpu_starting(unsigned int cpu)
0232 {
0233 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0,
0234 cpu);
0235 return 0;
0236 }
0237
0238 static int bcm2836_cpu_dying(unsigned int cpu)
0239 {
0240 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0,
0241 cpu);
0242 return 0;
0243 }
0244
0245 #define BITS_PER_MBOX 32
0246
0247 static void __init bcm2836_arm_irqchip_smp_init(void)
0248 {
0249 struct irq_fwspec ipi_fwspec = {
0250 .fwnode = intc.domain->fwnode,
0251 .param_count = 1,
0252 .param = {
0253 [0] = LOCAL_IRQ_MAILBOX0,
0254 },
0255 };
0256 int base_ipi, mux_irq;
0257
0258 mux_irq = irq_create_fwspec_mapping(&ipi_fwspec);
0259 if (WARN_ON(mux_irq <= 0))
0260 return;
0261
0262 ipi_domain = irq_domain_create_linear(intc.domain->fwnode,
0263 BITS_PER_MBOX, &ipi_domain_ops,
0264 NULL);
0265 if (WARN_ON(!ipi_domain))
0266 return;
0267
0268 ipi_domain->flags |= IRQ_DOMAIN_FLAG_IPI_SINGLE;
0269 irq_domain_update_bus_token(ipi_domain, DOMAIN_BUS_IPI);
0270
0271 base_ipi = __irq_domain_alloc_irqs(ipi_domain, -1, BITS_PER_MBOX,
0272 NUMA_NO_NODE, NULL,
0273 false, NULL);
0274
0275 if (WARN_ON(!base_ipi))
0276 return;
0277
0278 set_smp_ipi_range(base_ipi, BITS_PER_MBOX);
0279
0280 irq_set_chained_handler_and_data(mux_irq,
0281 bcm2836_arm_irqchip_handle_ipi, NULL);
0282
0283
0284 cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING,
0285 "irqchip/bcm2836:starting", bcm2836_cpu_starting,
0286 bcm2836_cpu_dying);
0287 }
0288 #else
0289 #define bcm2836_arm_irqchip_smp_init() do { } while(0)
0290 #endif
0291
0292 static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
0293 .xlate = irq_domain_xlate_onetwocell,
0294 .map = bcm2836_map,
0295 };
0296
0297
0298
0299
0300
0301
0302 static void bcm2835_init_local_timer_frequency(void)
0303 {
0304
0305
0306
0307
0308
0309 writel(0, intc.base + LOCAL_CONTROL);
0310
0311
0312
0313
0314
0315 writel(0x80000000, intc.base + LOCAL_PRESCALER);
0316 }
0317
0318 static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
0319 struct device_node *parent)
0320 {
0321 intc.base = of_iomap(node, 0);
0322 if (!intc.base) {
0323 panic("%pOF: unable to map local interrupt registers\n", node);
0324 }
0325
0326 bcm2835_init_local_timer_frequency();
0327
0328 intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
0329 &bcm2836_arm_irqchip_intc_ops,
0330 NULL);
0331 if (!intc.domain)
0332 panic("%pOF: unable to create IRQ domain\n", node);
0333
0334 irq_domain_update_bus_token(intc.domain, DOMAIN_BUS_WIRED);
0335
0336 bcm2836_arm_irqchip_smp_init();
0337
0338 set_handle_irq(bcm2836_arm_irqchip_handle_irq);
0339 return 0;
0340 }
0341
0342 IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc",
0343 bcm2836_arm_irqchip_l1_intc_of_init);