Merge tag 'for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux...
[deliverable/linux.git] / drivers / irqchip / irq-armada-370-xp.c
CommitLineData
9ae6f740
TP
1/*
2 * Marvell Armada 370 and Armada XP SoC IRQ handling
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Lior Amsalem <alior@marvell.com>
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 * Ben Dooks <ben.dooks@codethink.co.uk>
10 *
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
14 */
15
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/irq.h>
20#include <linux/interrupt.h>
bc69b8ad 21#include <linux/irqchip/chained_irq.h>
d7df84b3 22#include <linux/cpu.h>
9ae6f740
TP
23#include <linux/io.h>
24#include <linux/of_address.h>
25#include <linux/of_irq.h>
31f614ed 26#include <linux/of_pci.h>
9ae6f740 27#include <linux/irqdomain.h>
31f614ed 28#include <linux/slab.h>
0f077eb5 29#include <linux/syscore_ops.h>
31f614ed 30#include <linux/msi.h>
9ae6f740
TP
31#include <asm/mach/arch.h>
32#include <asm/exception.h>
344e873e 33#include <asm/smp_plat.h>
9339d432
TP
34#include <asm/mach/irq.h>
35
36#include "irqchip.h"
9ae6f740
TP
37
38/* Interrupt Controller Registers Map */
39#define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48)
40#define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C)
41
f3e16ccd 42#define ARMADA_370_XP_INT_CONTROL (0x00)
9ae6f740
TP
43#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30)
44#define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34)
3202bf01 45#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4)
8cc3cfc5 46#define ARMADA_370_XP_INT_SOURCE_CPU_MASK 0xF
758e8366 47#define ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid) ((BIT(0) | BIT(8)) << cpuid)
9ae6f740
TP
48
49#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44)
bc69b8ad 50#define ARMADA_375_PPI_CAUSE (0x10)
9ae6f740 51
344e873e
GC
52#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4)
53#define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc)
54#define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8)
55
3202bf01
GC
56#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28)
57
7f23f62f
GC
58#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ (5)
59
5ec69017
TP
60#define IPI_DOORBELL_START (0)
61#define IPI_DOORBELL_END (8)
62#define IPI_DOORBELL_MASK 0xFF
31f614ed
TP
63#define PCI_MSI_DOORBELL_START (16)
64#define PCI_MSI_DOORBELL_NR (16)
65#define PCI_MSI_DOORBELL_END (32)
66#define PCI_MSI_DOORBELL_MASK 0xFFFF0000
344e873e 67
9ae6f740
TP
68static void __iomem *per_cpu_int_base;
69static void __iomem *main_int_base;
70static struct irq_domain *armada_370_xp_mpic_domain;
0f077eb5 71static u32 doorbell_mask_reg;
5724be84 72static int parent_irq;
31f614ed
TP
73#ifdef CONFIG_PCI_MSI
74static struct irq_domain *armada_370_xp_msi_domain;
75static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
76static DEFINE_MUTEX(msi_used_lock);
77static phys_addr_t msi_doorbell_addr;
78#endif
9ae6f740 79
3202bf01
GC
80/*
81 * In SMP mode:
82 * For shared global interrupts, mask/unmask global enable bit
097ef18d 83 * For CPU interrupts, mask/unmask the calling CPU's bit
3202bf01 84 */
9ae6f740
TP
85static void armada_370_xp_irq_mask(struct irq_data *d)
86{
3202bf01
GC
87 irq_hw_number_t hwirq = irqd_to_hwirq(d);
88
7f23f62f 89 if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
3202bf01
GC
90 writel(hwirq, main_int_base +
91 ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
92 else
93 writel(hwirq, per_cpu_int_base +
94 ARMADA_370_XP_INT_SET_MASK_OFFS);
9ae6f740
TP
95}
96
97static void armada_370_xp_irq_unmask(struct irq_data *d)
98{
3202bf01
GC
99 irq_hw_number_t hwirq = irqd_to_hwirq(d);
100
7f23f62f 101 if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
3202bf01
GC
102 writel(hwirq, main_int_base +
103 ARMADA_370_XP_INT_SET_ENABLE_OFFS);
104 else
105 writel(hwirq, per_cpu_int_base +
106 ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
9ae6f740
TP
107}
108
31f614ed
TP
109#ifdef CONFIG_PCI_MSI
110
111static int armada_370_xp_alloc_msi(void)
112{
113 int hwirq;
114
115 mutex_lock(&msi_used_lock);
116 hwirq = find_first_zero_bit(&msi_used, PCI_MSI_DOORBELL_NR);
117 if (hwirq >= PCI_MSI_DOORBELL_NR)
118 hwirq = -ENOSPC;
119 else
120 set_bit(hwirq, msi_used);
121 mutex_unlock(&msi_used_lock);
122
123 return hwirq;
124}
125
126static void armada_370_xp_free_msi(int hwirq)
127{
128 mutex_lock(&msi_used_lock);
129 if (!test_bit(hwirq, msi_used))
130 pr_err("trying to free unused MSI#%d\n", hwirq);
131 else
132 clear_bit(hwirq, msi_used);
133 mutex_unlock(&msi_used_lock);
134}
135
c2791b80 136static int armada_370_xp_setup_msi_irq(struct msi_controller *chip,
31f614ed
TP
137 struct pci_dev *pdev,
138 struct msi_desc *desc)
139{
140 struct msi_msg msg;
da343fc7 141 int virq, hwirq;
31f614ed 142
3930115e
AG
143 /* We support MSI, but not MSI-X */
144 if (desc->msi_attrib.is_msix)
145 return -EINVAL;
146
31f614ed
TP
147 hwirq = armada_370_xp_alloc_msi();
148 if (hwirq < 0)
149 return hwirq;
150
151 virq = irq_create_mapping(armada_370_xp_msi_domain, hwirq);
152 if (!virq) {
153 armada_370_xp_free_msi(hwirq);
154 return -EINVAL;
155 }
156
157 irq_set_msi_desc(virq, desc);
158
159 msg.address_lo = msi_doorbell_addr;
160 msg.address_hi = 0;
161 msg.data = 0xf00 | (hwirq + 16);
162
83a18912 163 pci_write_msi_msg(virq, &msg);
31f614ed
TP
164 return 0;
165}
166
c2791b80 167static void armada_370_xp_teardown_msi_irq(struct msi_controller *chip,
31f614ed
TP
168 unsigned int irq)
169{
170 struct irq_data *d = irq_get_irq_data(irq);
ff3c6645
NG
171 unsigned long hwirq = d->hwirq;
172
31f614ed 173 irq_dispose_mapping(irq);
ff3c6645 174 armada_370_xp_free_msi(hwirq);
31f614ed
TP
175}
176
177static struct irq_chip armada_370_xp_msi_irq_chip = {
178 .name = "armada_370_xp_msi_irq",
280510f1
TG
179 .irq_enable = pci_msi_unmask_irq,
180 .irq_disable = pci_msi_mask_irq,
181 .irq_mask = pci_msi_mask_irq,
182 .irq_unmask = pci_msi_unmask_irq,
31f614ed
TP
183};
184
185static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq,
186 irq_hw_number_t hw)
187{
188 irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip,
189 handle_simple_irq);
190 set_irq_flags(virq, IRQF_VALID);
191
192 return 0;
193}
194
195static const struct irq_domain_ops armada_370_xp_msi_irq_ops = {
196 .map = armada_370_xp_msi_map,
197};
198
199static int armada_370_xp_msi_init(struct device_node *node,
200 phys_addr_t main_int_phys_base)
201{
c2791b80 202 struct msi_controller *msi_chip;
31f614ed
TP
203 u32 reg;
204 int ret;
205
206 msi_doorbell_addr = main_int_phys_base +
207 ARMADA_370_XP_SW_TRIG_INT_OFFS;
208
209 msi_chip = kzalloc(sizeof(*msi_chip), GFP_KERNEL);
210 if (!msi_chip)
211 return -ENOMEM;
212
213 msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
214 msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
215 msi_chip->of_node = node;
216
217 armada_370_xp_msi_domain =
218 irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR,
219 &armada_370_xp_msi_irq_ops,
220 NULL);
221 if (!armada_370_xp_msi_domain) {
222 kfree(msi_chip);
223 return -ENOMEM;
224 }
225
226 ret = of_pci_msi_chip_add(msi_chip);
227 if (ret < 0) {
228 irq_domain_remove(armada_370_xp_msi_domain);
229 kfree(msi_chip);
230 return ret;
231 }
232
233 reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS)
234 | PCI_MSI_DOORBELL_MASK;
235
236 writel(reg, per_cpu_int_base +
237 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
238
239 /* Unmask IPI interrupt */
240 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
241
242 return 0;
243}
244#else
245static inline int armada_370_xp_msi_init(struct device_node *node,
246 phys_addr_t main_int_phys_base)
247{
248 return 0;
249}
250#endif
251
344e873e 252#ifdef CONFIG_SMP
19e61d41
AE
253static DEFINE_RAW_SPINLOCK(irq_controller_lock);
254
344e873e
GC
255static int armada_xp_set_affinity(struct irq_data *d,
256 const struct cpumask *mask_val, bool force)
257{
3202bf01 258 irq_hw_number_t hwirq = irqd_to_hwirq(d);
8cc3cfc5 259 unsigned long reg, mask;
3202bf01
GC
260 int cpu;
261
8cc3cfc5
TG
262 /* Select a single core from the affinity mask which is online */
263 cpu = cpumask_any_and(mask_val, cpu_online_mask);
264 mask = 1UL << cpu_logical_map(cpu);
3202bf01
GC
265
266 raw_spin_lock(&irq_controller_lock);
3202bf01 267 reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
8cc3cfc5 268 reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask;
3202bf01 269 writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
3202bf01
GC
270 raw_spin_unlock(&irq_controller_lock);
271
1dacf194 272 return IRQ_SET_MASK_OK;
344e873e
GC
273}
274#endif
275
9ae6f740
TP
276static struct irq_chip armada_370_xp_irq_chip = {
277 .name = "armada_370_xp_irq",
278 .irq_mask = armada_370_xp_irq_mask,
279 .irq_mask_ack = armada_370_xp_irq_mask,
280 .irq_unmask = armada_370_xp_irq_unmask,
344e873e
GC
281#ifdef CONFIG_SMP
282 .irq_set_affinity = armada_xp_set_affinity,
283#endif
9ae6f740
TP
284};
285
286static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
287 unsigned int virq, irq_hw_number_t hw)
288{
289 armada_370_xp_irq_mask(irq_get_irq_data(virq));
600468d0
GC
290 if (hw != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
291 writel(hw, per_cpu_int_base +
292 ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
293 else
294 writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
9ae6f740 295 irq_set_status_flags(virq, IRQ_LEVEL);
3a6f08a3 296
7f23f62f 297 if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) {
3a6f08a3
GC
298 irq_set_percpu_devid(virq);
299 irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
300 handle_percpu_devid_irq);
301
302 } else {
303 irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
304 handle_level_irq);
305 }
9ae6f740
TP
306 set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
307
308 return 0;
309}
310
344e873e 311#ifdef CONFIG_SMP
ef37d337
TP
312static void armada_mpic_send_doorbell(const struct cpumask *mask,
313 unsigned int irq)
344e873e
GC
314{
315 int cpu;
316 unsigned long map = 0;
317
318 /* Convert our logical CPU mask into a physical one. */
319 for_each_cpu(cpu, mask)
320 map |= 1 << cpu_logical_map(cpu);
321
322 /*
323 * Ensure that stores to Normal memory are visible to the
324 * other CPUs before issuing the IPI.
325 */
326 dsb();
327
328 /* submit softirq */
329 writel((map << 8) | irq, main_int_base +
330 ARMADA_370_XP_SW_TRIG_INT_OFFS);
331}
332
d7df84b3 333static void armada_xp_mpic_smp_cpu_init(void)
344e873e 334{
b73842b7
TP
335 u32 control;
336 int nr_irqs, i;
337
338 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
339 nr_irqs = (control >> 2) & 0x3ff;
340
341 for (i = 0; i < nr_irqs; i++)
342 writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS);
343
344e873e
GC
344 /* Clear pending IPIs */
345 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
346
347 /* Enable first 8 IPIs */
5ec69017 348 writel(IPI_DOORBELL_MASK, per_cpu_int_base +
344e873e
GC
349 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
350
351 /* Unmask IPI interrupt */
352 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
353}
d7df84b3
TP
354
355static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
356 unsigned long action, void *hcpu)
357{
358 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
359 armada_xp_mpic_smp_cpu_init();
5724be84 360
d7df84b3
TP
361 return NOTIFY_OK;
362}
363
364static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
365 .notifier_call = armada_xp_mpic_secondary_init,
366 .priority = 100,
367};
368
5724be84
MR
369static int mpic_cascaded_secondary_init(struct notifier_block *nfb,
370 unsigned long action, void *hcpu)
371{
372 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
373 enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
374
375 return NOTIFY_OK;
376}
377
378static struct notifier_block mpic_cascaded_cpu_notifier = {
379 .notifier_call = mpic_cascaded_secondary_init,
380 .priority = 100,
381};
382
344e873e
GC
383#endif /* CONFIG_SMP */
384
9ae6f740
TP
385static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
386 .map = armada_370_xp_mpic_irq_map,
387 .xlate = irq_domain_xlate_onecell,
388};
389
9b8cf779 390#ifdef CONFIG_PCI_MSI
bc69b8ad 391static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
9b8cf779
EG
392{
393 u32 msimask, msinr;
394
395 msimask = readl_relaxed(per_cpu_int_base +
396 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
397 & PCI_MSI_DOORBELL_MASK;
398
399 writel(~msimask, per_cpu_int_base +
400 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
401
402 for (msinr = PCI_MSI_DOORBELL_START;
403 msinr < PCI_MSI_DOORBELL_END; msinr++) {
404 int irq;
405
406 if (!(msimask & BIT(msinr)))
407 continue;
408
e89c6a06
MZ
409 if (is_chained) {
410 irq = irq_find_mapping(armada_370_xp_msi_domain,
411 msinr - 16);
bc69b8ad 412 generic_handle_irq(irq);
e89c6a06
MZ
413 } else {
414 irq = msinr - 16;
415 handle_domain_irq(armada_370_xp_msi_domain,
416 irq, regs);
417 }
9b8cf779
EG
418 }
419}
420#else
bc69b8ad 421static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {}
9b8cf779
EG
422#endif
423
bc69b8ad
EG
424static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq,
425 struct irq_desc *desc)
426{
427 struct irq_chip *chip = irq_get_chip(irq);
758e8366 428 unsigned long irqmap, irqn, irqsrc, cpuid;
bc69b8ad
EG
429 unsigned int cascade_irq;
430
431 chained_irq_enter(chip, desc);
432
433 irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE);
758e8366 434 cpuid = cpu_logical_map(smp_processor_id());
bc69b8ad
EG
435
436 for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) {
758e8366
GJ
437 irqsrc = readl_relaxed(main_int_base +
438 ARMADA_370_XP_INT_SOURCE_CTL(irqn));
439
440 /* Check if the interrupt is not masked on current CPU.
441 * Test IRQ (0-1) and FIQ (8-9) mask bits.
442 */
443 if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid)))
444 continue;
445
446 if (irqn == 1) {
447 armada_370_xp_handle_msi_irq(NULL, true);
448 continue;
449 }
450
bc69b8ad
EG
451 cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn);
452 generic_handle_irq(cascade_irq);
453 }
454
455 chained_irq_exit(chip, desc);
456}
457
8783dd3a 458static void __exception_irq_entry
9339d432 459armada_370_xp_handle_irq(struct pt_regs *regs)
9ae6f740
TP
460{
461 u32 irqstat, irqnr;
462
463 do {
464 irqstat = readl_relaxed(per_cpu_int_base +
465 ARMADA_370_XP_CPU_INTACK_OFFS);
466 irqnr = irqstat & 0x3FF;
467
344e873e
GC
468 if (irqnr > 1022)
469 break;
470
31f614ed 471 if (irqnr > 1) {
e89c6a06
MZ
472 handle_domain_irq(armada_370_xp_mpic_domain,
473 irqnr, regs);
9ae6f740
TP
474 continue;
475 }
31f614ed 476
31f614ed 477 /* MSI handling */
9b8cf779 478 if (irqnr == 1)
bc69b8ad 479 armada_370_xp_handle_msi_irq(regs, false);
31f614ed 480
344e873e
GC
481#ifdef CONFIG_SMP
482 /* IPI Handling */
483 if (irqnr == 0) {
484 u32 ipimask, ipinr;
485
486 ipimask = readl_relaxed(per_cpu_int_base +
487 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS)
5ec69017 488 & IPI_DOORBELL_MASK;
344e873e 489
a6f089e9 490 writel(~ipimask, per_cpu_int_base +
344e873e
GC
491 ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
492
493 /* Handle all pending doorbells */
5ec69017
TP
494 for (ipinr = IPI_DOORBELL_START;
495 ipinr < IPI_DOORBELL_END; ipinr++) {
344e873e
GC
496 if (ipimask & (0x1 << ipinr))
497 handle_IPI(ipinr, regs);
498 }
499 continue;
500 }
501#endif
9ae6f740 502
9ae6f740
TP
503 } while (1);
504}
505
0f077eb5
TP
506static int armada_370_xp_mpic_suspend(void)
507{
508 doorbell_mask_reg = readl(per_cpu_int_base +
509 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
510 return 0;
511}
512
513static void armada_370_xp_mpic_resume(void)
514{
515 int nirqs;
516 irq_hw_number_t irq;
517
518 /* Re-enable interrupts */
519 nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
520 for (irq = 0; irq < nirqs; irq++) {
521 struct irq_data *data;
522 int virq;
523
524 virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
525 if (virq == 0)
526 continue;
527
528 if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
529 writel(irq, per_cpu_int_base +
530 ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
531 else
532 writel(irq, main_int_base +
533 ARMADA_370_XP_INT_SET_ENABLE_OFFS);
534
535 data = irq_get_irq_data(virq);
536 if (!irqd_irq_disabled(data))
537 armada_370_xp_irq_unmask(data);
538 }
539
540 /* Reconfigure doorbells for IPIs and MSIs */
541 writel(doorbell_mask_reg,
542 per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
543 if (doorbell_mask_reg & IPI_DOORBELL_MASK)
544 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
545 if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
546 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
547}
548
549struct syscore_ops armada_370_xp_mpic_syscore_ops = {
550 .suspend = armada_370_xp_mpic_suspend,
551 .resume = armada_370_xp_mpic_resume,
552};
553
b313ada8
TP
554static int __init armada_370_xp_mpic_of_init(struct device_node *node,
555 struct device_node *parent)
9ae6f740 556{
627dfcc2 557 struct resource main_int_res, per_cpu_int_res;
5724be84 558 int nr_irqs, i;
b313ada8
TP
559 u32 control;
560
627dfcc2
TP
561 BUG_ON(of_address_to_resource(node, 0, &main_int_res));
562 BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res));
b313ada8 563
627dfcc2
TP
564 BUG_ON(!request_mem_region(main_int_res.start,
565 resource_size(&main_int_res),
566 node->full_name));
567 BUG_ON(!request_mem_region(per_cpu_int_res.start,
568 resource_size(&per_cpu_int_res),
569 node->full_name));
570
571 main_int_base = ioremap(main_int_res.start,
572 resource_size(&main_int_res));
b313ada8 573 BUG_ON(!main_int_base);
627dfcc2
TP
574
575 per_cpu_int_base = ioremap(per_cpu_int_res.start,
576 resource_size(&per_cpu_int_res));
b313ada8
TP
577 BUG_ON(!per_cpu_int_base);
578
579 control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL);
b73842b7
TP
580 nr_irqs = (control >> 2) & 0x3ff;
581
582 for (i = 0; i < nr_irqs; i++)
583 writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
b313ada8
TP
584
585 armada_370_xp_mpic_domain =
b73842b7 586 irq_domain_add_linear(node, nr_irqs,
b313ada8
TP
587 &armada_370_xp_mpic_irq_ops, NULL);
588
627dfcc2 589 BUG_ON(!armada_370_xp_mpic_domain);
b313ada8 590
b313ada8
TP
591#ifdef CONFIG_SMP
592 armada_xp_mpic_smp_cpu_init();
d792b1e9 593#endif
b313ada8 594
31f614ed
TP
595 armada_370_xp_msi_init(node, main_int_res.start);
596
bc69b8ad
EG
597 parent_irq = irq_of_parse_and_map(node, 0);
598 if (parent_irq <= 0) {
599 irq_set_default_host(armada_370_xp_mpic_domain);
600 set_handle_irq(armada_370_xp_handle_irq);
ef37d337
TP
601#ifdef CONFIG_SMP
602 set_smp_cross_call(armada_mpic_send_doorbell);
d7df84b3 603 register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
ef37d337 604#endif
bc69b8ad 605 } else {
5724be84
MR
606#ifdef CONFIG_SMP
607 register_cpu_notifier(&mpic_cascaded_cpu_notifier);
608#endif
bc69b8ad
EG
609 irq_set_chained_handler(parent_irq,
610 armada_370_xp_mpic_handle_cascade_irq);
611 }
b313ada8 612
0f077eb5
TP
613 register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
614
b313ada8 615 return 0;
9ae6f740 616}
b313ada8 617
9339d432 618IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init);
This page took 0.280534 seconds and 5 git commands to generate.