Commit | Line | Data |
---|---|---|
5ad36c5f | 1 | /* |
938fa349 | 2 | * Copyright (C) 2011 Google, Inc. |
5ad36c5f EG |
3 | * |
4 | * Author: | |
938fa349 | 5 | * Colin Cross <ccross@android.com> |
5ad36c5f | 6 | * |
460907bc GK |
7 | * Copyright (C) 2010, NVIDIA Corporation |
8 | * | |
5ad36c5f EG |
9 | * This software is licensed under the terms of the GNU General Public |
10 | * License version 2, as published by the Free Software Foundation, and | |
11 | * may be copied, distributed, and modified under those terms. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | */ | |
19 | ||
20 | #include <linux/kernel.h> | |
5ad36c5f EG |
21 | #include <linux/interrupt.h> |
22 | #include <linux/irq.h> | |
23 | #include <linux/io.h> | |
0d4f7479 | 24 | #include <linux/of.h> |
5ad36c5f EG |
25 | |
26 | #include <asm/hardware/gic.h> | |
27 | ||
28 | #include <mach/iomap.h> | |
29 | ||
30 | #include "board.h" | |
31 | ||
d1d8c666 CC |
32 | #define ICTLR_CPU_IEP_VFIQ 0x08 |
33 | #define ICTLR_CPU_IEP_FIR 0x14 | |
34 | #define ICTLR_CPU_IEP_FIR_SET 0x18 | |
35 | #define ICTLR_CPU_IEP_FIR_CLR 0x1c | |
36 | ||
37 | #define ICTLR_CPU_IER 0x20 | |
38 | #define ICTLR_CPU_IER_SET 0x24 | |
39 | #define ICTLR_CPU_IER_CLR 0x28 | |
40 | #define ICTLR_CPU_IEP_CLASS 0x2C | |
41 | ||
42 | #define ICTLR_COP_IER 0x30 | |
43 | #define ICTLR_COP_IER_SET 0x34 | |
44 | #define ICTLR_COP_IER_CLR 0x38 | |
45 | #define ICTLR_COP_IEP_CLASS 0x3c | |
46 | ||
d1d8c666 CC |
47 | #define FIRST_LEGACY_IRQ 32 |
48 | ||
caa4868e PDS |
49 | static int num_ictlrs; |
50 | ||
d1d8c666 CC |
51 | static void __iomem *ictlr_reg_base[] = { |
52 | IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE), | |
53 | IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE), | |
54 | IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE), | |
55 | IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE), | |
caa4868e | 56 | IO_ADDRESS(TEGRA_QUINARY_ICTLR_BASE), |
d1d8c666 CC |
57 | }; |
58 | ||
59 | static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) | |
60 | { | |
61 | void __iomem *base; | |
62 | u32 mask; | |
63 | ||
64 | BUG_ON(irq < FIRST_LEGACY_IRQ || | |
caa4868e | 65 | irq >= FIRST_LEGACY_IRQ + num_ictlrs * 32); |
d1d8c666 CC |
66 | |
67 | base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32]; | |
68 | mask = BIT((irq - FIRST_LEGACY_IRQ) % 32); | |
69 | ||
70 | __raw_writel(mask, base + reg); | |
71 | } | |
72 | ||
3524b70e CC |
73 | static void tegra_mask(struct irq_data *d) |
74 | { | |
d1d8c666 CC |
75 | if (d->irq < FIRST_LEGACY_IRQ) |
76 | return; | |
77 | ||
78 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR); | |
3524b70e | 79 | } |
460907bc | 80 | |
3524b70e | 81 | static void tegra_unmask(struct irq_data *d) |
460907bc | 82 | { |
d1d8c666 CC |
83 | if (d->irq < FIRST_LEGACY_IRQ) |
84 | return; | |
85 | ||
86 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET); | |
460907bc | 87 | } |
460907bc | 88 | |
26d902c0 CC |
89 | static void tegra_ack(struct irq_data *d) |
90 | { | |
d1d8c666 CC |
91 | if (d->irq < FIRST_LEGACY_IRQ) |
92 | return; | |
93 | ||
94 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); | |
26d902c0 CC |
95 | } |
96 | ||
4bd66cfd CC |
97 | static void tegra_eoi(struct irq_data *d) |
98 | { | |
99 | if (d->irq < FIRST_LEGACY_IRQ) | |
100 | return; | |
101 | ||
102 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); | |
103 | } | |
104 | ||
26d902c0 CC |
105 | static int tegra_retrigger(struct irq_data *d) |
106 | { | |
d1d8c666 | 107 | if (d->irq < FIRST_LEGACY_IRQ) |
938fa349 CC |
108 | return 0; |
109 | ||
d1d8c666 CC |
110 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET); |
111 | ||
26d902c0 CC |
112 | return 1; |
113 | } | |
114 | ||
5ad36c5f EG |
115 | void __init tegra_init_irq(void) |
116 | { | |
d1d8c666 | 117 | int i; |
caa4868e PDS |
118 | void __iomem *distbase; |
119 | ||
120 | distbase = IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE); | |
121 | num_ictlrs = readl_relaxed(distbase + GIC_DIST_CTR) & 0x1f; | |
122 | ||
123 | if (num_ictlrs > ARRAY_SIZE(ictlr_reg_base)) { | |
124 | WARN(1, "Too many (%d) interrupt controllers found. Maximum is %d.", | |
125 | num_ictlrs, ARRAY_SIZE(ictlr_reg_base)); | |
126 | num_ictlrs = ARRAY_SIZE(ictlr_reg_base); | |
127 | } | |
d1d8c666 | 128 | |
caa4868e | 129 | for (i = 0; i < num_ictlrs; i++) { |
d1d8c666 CC |
130 | void __iomem *ictlr = ictlr_reg_base[i]; |
131 | writel(~0, ictlr + ICTLR_CPU_IER_CLR); | |
132 | writel(0, ictlr + ICTLR_CPU_IEP_CLASS); | |
133 | } | |
460907bc | 134 | |
938fa349 | 135 | gic_arch_extn.irq_ack = tegra_ack; |
4bd66cfd | 136 | gic_arch_extn.irq_eoi = tegra_eoi; |
938fa349 CC |
137 | gic_arch_extn.irq_mask = tegra_mask; |
138 | gic_arch_extn.irq_unmask = tegra_unmask; | |
139 | gic_arch_extn.irq_retrigger = tegra_retrigger; | |
140 | ||
0d4f7479 | 141 | /* |
142 | * Check if there is a devicetree present, since the GIC will be | |
143 | * initialized elsewhere under DT. | |
144 | */ | |
145 | if (!of_have_populated_dt()) | |
caa4868e | 146 | gic_init(0, 29, distbase, |
0d4f7479 | 147 | IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100)); |
460907bc | 148 | } |