root/drivers/irqchip/irq-bcm2836.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bcm2836_arm_irqchip_mask_per_cpu_irq
  2. bcm2836_arm_irqchip_unmask_per_cpu_irq
  3. bcm2836_arm_irqchip_mask_timer_irq
  4. bcm2836_arm_irqchip_unmask_timer_irq
  5. bcm2836_arm_irqchip_mask_pmu_irq
  6. bcm2836_arm_irqchip_unmask_pmu_irq
  7. bcm2836_arm_irqchip_mask_gpu_irq
  8. bcm2836_arm_irqchip_unmask_gpu_irq
  9. bcm2836_map
  10. bcm2836_arm_irqchip_handle_irq
  11. bcm2836_arm_irqchip_send_ipi
  12. bcm2836_cpu_starting
  13. bcm2836_cpu_dying
  14. bcm2836_arm_irqchip_smp_init
  15. bcm2835_init_local_timer_frequency
  16. bcm2836_arm_irqchip_l1_intc_of_init

   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);

/* [<][>][^][v][top][bottom][index][help] */