irqchip/bcm2836: Fix initialization of the LOCAL_IRQ_CNT timers
[deliverable/linux.git] / drivers / irqchip / irq-bcm2836.c
CommitLineData
1a15aaa9
EA
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
401667bb
EA
24#define LOCAL_CONTROL 0x000
25#define LOCAL_PRESCALER 0x008
26
1a15aaa9
EA
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 * Mailbox0 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/* Mailbox0 write-to-clear bits. */
63#define LOCAL_MAILBOX0_CLR0 0x0c0
64
65#define LOCAL_IRQ_CNTPSIRQ 0
66#define LOCAL_IRQ_CNTPNSIRQ 1
67#define LOCAL_IRQ_CNTHPIRQ 2
68#define LOCAL_IRQ_CNTVIRQ 3
69#define LOCAL_IRQ_MAILBOX0 4
70#define LOCAL_IRQ_MAILBOX1 5
71#define LOCAL_IRQ_MAILBOX2 6
72#define LOCAL_IRQ_MAILBOX3 7
73#define LOCAL_IRQ_GPU_FAST 8
74#define LOCAL_IRQ_PMU_FAST 9
75#define LAST_IRQ LOCAL_IRQ_PMU_FAST
76
77struct bcm2836_arm_irqchip_intc {
78 struct irq_domain *domain;
79 void __iomem *base;
80};
81
82static struct bcm2836_arm_irqchip_intc intc __read_mostly;
83
84static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset,
85 unsigned int bit,
86 int cpu)
87{
88 void __iomem *reg = intc.base + reg_offset + 4 * cpu;
89
90 writel(readl(reg) & ~BIT(bit), reg);
91}
92
93static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset,
94 unsigned int bit,
95 int cpu)
96{
97 void __iomem *reg = intc.base + reg_offset + 4 * cpu;
98
99 writel(readl(reg) | BIT(bit), reg);
100}
101
102static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d)
103{
104 bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
105 d->hwirq - LOCAL_IRQ_CNTPSIRQ,
106 smp_processor_id());
107}
108
109static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d)
110{
111 bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0,
112 d->hwirq - LOCAL_IRQ_CNTPSIRQ,
113 smp_processor_id());
114}
115
116static struct irq_chip bcm2836_arm_irqchip_timer = {
117 .name = "bcm2836-timer",
118 .irq_mask = bcm2836_arm_irqchip_mask_timer_irq,
119 .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq,
120};
121
122static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d)
123{
124 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR);
125}
126
127static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d)
128{
129 writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET);
130}
131
132static struct irq_chip bcm2836_arm_irqchip_pmu = {
133 .name = "bcm2836-pmu",
134 .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq,
135 .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq,
136};
137
138static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d)
139{
140}
141
142static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d)
143{
144}
145
146static struct irq_chip bcm2836_arm_irqchip_gpu = {
147 .name = "bcm2836-gpu",
148 .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq,
149 .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq,
150};
151
152static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip)
153{
154 int irq = irq_create_mapping(intc.domain, hwirq);
155
156 irq_set_percpu_devid(irq);
157 irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq);
158 irq_set_status_flags(irq, IRQ_NOAUTOEN);
159}
160
161static void
162__exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
163{
164 int cpu = smp_processor_id();
165 u32 stat;
166
167 stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
168 if (stat & 0x10) {
169#ifdef CONFIG_SMP
170 void __iomem *mailbox0 = (intc.base +
171 LOCAL_MAILBOX0_CLR0 + 16 * cpu);
172 u32 mbox_val = readl(mailbox0);
173 u32 ipi = ffs(mbox_val) - 1;
174
175 writel(1 << ipi, mailbox0);
176 handle_IPI(ipi, regs);
177#endif
178 } else {
179 u32 hwirq = ffs(stat) - 1;
180
181 handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
182 }
183}
184
185#ifdef CONFIG_SMP
186static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
187 unsigned int ipi)
188{
189 int cpu;
190 void __iomem *mailbox0_base = intc.base + LOCAL_MAILBOX0_SET0;
191
192 /*
193 * Ensure that stores to normal memory are visible to the
194 * other CPUs before issuing the IPI.
195 */
196 dsb();
197
198 for_each_cpu(cpu, mask) {
199 writel(1 << ipi, mailbox0_base + 16 * cpu);
200 }
201}
202
203/* Unmasks the IPI on the CPU when it's online. */
204static int bcm2836_arm_irqchip_cpu_notify(struct notifier_block *nfb,
205 unsigned long action, void *hcpu)
206{
207 unsigned int cpu = (unsigned long)hcpu;
208 unsigned int int_reg = LOCAL_MAILBOX_INT_CONTROL0;
209 unsigned int mailbox = 0;
210
211 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
212 bcm2836_arm_irqchip_unmask_per_cpu_irq(int_reg, mailbox, cpu);
213 else if (action == CPU_DYING)
214 bcm2836_arm_irqchip_mask_per_cpu_irq(int_reg, mailbox, cpu);
215
216 return NOTIFY_OK;
217}
218
219static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
220 .notifier_call = bcm2836_arm_irqchip_cpu_notify,
221 .priority = 100,
222};
223#endif
224
225static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
226 .xlate = irq_domain_xlate_onecell
227};
228
229static void
230bcm2836_arm_irqchip_smp_init(void)
231{
232#ifdef CONFIG_SMP
233 /* Unmask IPIs to the boot CPU. */
234 bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier,
235 CPU_STARTING,
236 (void *)smp_processor_id());
237 register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
238
239 set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
240#endif
241}
242
401667bb
EA
243/*
244 * The LOCAL_IRQ_CNT* timer firings are based off of the external
245 * oscillator with some scaling. The firmware sets up CNTFRQ to
246 * report 19.2Mhz, but doesn't set up the scaling registers.
247 */
248static void bcm2835_init_local_timer_frequency(void)
249{
250 /*
251 * Set the timer to source from the 19.2Mhz crystal clock (bit
252 * 8 unset), and only increment by 1 instead of 2 (bit 9
253 * unset).
254 */
255 writel(0, intc.base + LOCAL_CONTROL);
256
257 /*
258 * Set the timer prescaler to 1:1 (timer freq = input freq *
259 * 2**31 / prescaler)
260 */
261 writel(0x80000000, intc.base + LOCAL_PRESCALER);
262}
263
1a15aaa9
EA
264static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
265 struct device_node *parent)
266{
267 intc.base = of_iomap(node, 0);
268 if (!intc.base) {
269 panic("%s: unable to map local interrupt registers\n",
270 node->full_name);
271 }
272
401667bb
EA
273 bcm2835_init_local_timer_frequency();
274
1a15aaa9
EA
275 intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
276 &bcm2836_arm_irqchip_intc_ops,
277 NULL);
278 if (!intc.domain)
279 panic("%s: unable to create IRQ domain\n", node->full_name);
280
281 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPSIRQ,
282 &bcm2836_arm_irqchip_timer);
283 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTPNSIRQ,
284 &bcm2836_arm_irqchip_timer);
285 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTHPIRQ,
286 &bcm2836_arm_irqchip_timer);
287 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_CNTVIRQ,
288 &bcm2836_arm_irqchip_timer);
289 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_GPU_FAST,
290 &bcm2836_arm_irqchip_gpu);
291 bcm2836_arm_irqchip_register_irq(LOCAL_IRQ_PMU_FAST,
292 &bcm2836_arm_irqchip_pmu);
293
294 bcm2836_arm_irqchip_smp_init();
295
296 set_handle_irq(bcm2836_arm_irqchip_handle_irq);
297 return 0;
298}
299
300IRQCHIP_DECLARE(bcm2836_arm_irqchip_l1_intc, "brcm,bcm2836-l1-intc",
301 bcm2836_arm_irqchip_l1_intc_of_init);
This page took 0.051186 seconds and 5 git commands to generate.