2 * Driver code for Tegra's Legacy Interrupt Controller
4 * Author: Marc Zyngier <marc.zyngier@arm.com>
6 * Heavily based on the original arch/arm/mach-tegra/irq.c code:
7 * Copyright (C) 2011 Google, Inc.
10 * Colin Cross <ccross@android.com>
12 * Copyright (C) 2010,2013, NVIDIA Corporation
14 * This software is licensed under the terms of the GNU General Public
15 * License version 2, as published by the Free Software Foundation, and
16 * may be copied, distributed, and modified under those terms.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
26 #include <linux/irq.h>
27 #include <linux/irqchip.h>
28 #include <linux/irqdomain.h>
29 #include <linux/of_address.h>
30 #include <linux/slab.h>
31 #include <linux/syscore_ops.h>
33 #include <dt-bindings/interrupt-controller/arm-gic.h>
35 #define ICTLR_CPU_IEP_VFIQ 0x08
36 #define ICTLR_CPU_IEP_FIR 0x14
37 #define ICTLR_CPU_IEP_FIR_SET 0x18
38 #define ICTLR_CPU_IEP_FIR_CLR 0x1c
40 #define ICTLR_CPU_IER 0x20
41 #define ICTLR_CPU_IER_SET 0x24
42 #define ICTLR_CPU_IER_CLR 0x28
43 #define ICTLR_CPU_IEP_CLASS 0x2C
45 #define ICTLR_COP_IER 0x30
46 #define ICTLR_COP_IER_SET 0x34
47 #define ICTLR_COP_IER_CLR 0x38
48 #define ICTLR_COP_IEP_CLASS 0x3c
50 #define TEGRA_MAX_NUM_ICTLRS 6
52 static unsigned int num_ictlrs
;
54 struct tegra_ictlr_soc
{
55 unsigned int num_ictlrs
;
58 static const struct tegra_ictlr_soc tegra20_ictlr_soc
= {
62 static const struct tegra_ictlr_soc tegra30_ictlr_soc
= {
66 static const struct tegra_ictlr_soc tegra210_ictlr_soc
= {
70 static const struct of_device_id ictlr_matches
[] = {
71 { .compatible
= "nvidia,tegra210-ictlr", .data
= &tegra210_ictlr_soc
},
72 { .compatible
= "nvidia,tegra30-ictlr", .data
= &tegra30_ictlr_soc
},
73 { .compatible
= "nvidia,tegra20-ictlr", .data
= &tegra20_ictlr_soc
},
77 struct tegra_ictlr_info
{
78 void __iomem
*base
[TEGRA_MAX_NUM_ICTLRS
];
79 #ifdef CONFIG_PM_SLEEP
80 u32 cop_ier
[TEGRA_MAX_NUM_ICTLRS
];
81 u32 cop_iep
[TEGRA_MAX_NUM_ICTLRS
];
82 u32 cpu_ier
[TEGRA_MAX_NUM_ICTLRS
];
83 u32 cpu_iep
[TEGRA_MAX_NUM_ICTLRS
];
85 u32 ictlr_wake_mask
[TEGRA_MAX_NUM_ICTLRS
];
89 static struct tegra_ictlr_info
*lic
;
91 static inline void tegra_ictlr_write_mask(struct irq_data
*d
, unsigned long reg
)
93 void __iomem
*base
= (void __iomem __force
*)d
->chip_data
;
96 mask
= BIT(d
->hwirq
% 32);
97 writel_relaxed(mask
, base
+ reg
);
100 static void tegra_mask(struct irq_data
*d
)
102 tegra_ictlr_write_mask(d
, ICTLR_CPU_IER_CLR
);
103 irq_chip_mask_parent(d
);
106 static void tegra_unmask(struct irq_data
*d
)
108 tegra_ictlr_write_mask(d
, ICTLR_CPU_IER_SET
);
109 irq_chip_unmask_parent(d
);
112 static void tegra_eoi(struct irq_data
*d
)
114 tegra_ictlr_write_mask(d
, ICTLR_CPU_IEP_FIR_CLR
);
115 irq_chip_eoi_parent(d
);
118 static int tegra_retrigger(struct irq_data
*d
)
120 tegra_ictlr_write_mask(d
, ICTLR_CPU_IEP_FIR_SET
);
121 return irq_chip_retrigger_hierarchy(d
);
124 #ifdef CONFIG_PM_SLEEP
125 static int tegra_set_wake(struct irq_data
*d
, unsigned int enable
)
131 mask
= BIT(irq
% 32);
133 lic
->ictlr_wake_mask
[index
] |= mask
;
135 lic
->ictlr_wake_mask
[index
] &= ~mask
;
138 * Do *not* call into the parent, as the GIC doesn't have any
139 * wake-up facility...
144 static int tegra_ictlr_suspend(void)
149 local_irq_save(flags
);
150 for (i
= 0; i
< num_ictlrs
; i
++) {
151 void __iomem
*ictlr
= lic
->base
[i
];
153 /* Save interrupt state */
154 lic
->cpu_ier
[i
] = readl_relaxed(ictlr
+ ICTLR_CPU_IER
);
155 lic
->cpu_iep
[i
] = readl_relaxed(ictlr
+ ICTLR_CPU_IEP_CLASS
);
156 lic
->cop_ier
[i
] = readl_relaxed(ictlr
+ ICTLR_COP_IER
);
157 lic
->cop_iep
[i
] = readl_relaxed(ictlr
+ ICTLR_COP_IEP_CLASS
);
159 /* Disable COP interrupts */
160 writel_relaxed(~0ul, ictlr
+ ICTLR_COP_IER_CLR
);
162 /* Disable CPU interrupts */
163 writel_relaxed(~0ul, ictlr
+ ICTLR_CPU_IER_CLR
);
165 /* Enable the wakeup sources of ictlr */
166 writel_relaxed(lic
->ictlr_wake_mask
[i
], ictlr
+ ICTLR_CPU_IER_SET
);
168 local_irq_restore(flags
);
173 static void tegra_ictlr_resume(void)
178 local_irq_save(flags
);
179 for (i
= 0; i
< num_ictlrs
; i
++) {
180 void __iomem
*ictlr
= lic
->base
[i
];
182 writel_relaxed(lic
->cpu_iep
[i
],
183 ictlr
+ ICTLR_CPU_IEP_CLASS
);
184 writel_relaxed(~0ul, ictlr
+ ICTLR_CPU_IER_CLR
);
185 writel_relaxed(lic
->cpu_ier
[i
],
186 ictlr
+ ICTLR_CPU_IER_SET
);
187 writel_relaxed(lic
->cop_iep
[i
],
188 ictlr
+ ICTLR_COP_IEP_CLASS
);
189 writel_relaxed(~0ul, ictlr
+ ICTLR_COP_IER_CLR
);
190 writel_relaxed(lic
->cop_ier
[i
],
191 ictlr
+ ICTLR_COP_IER_SET
);
193 local_irq_restore(flags
);
196 static struct syscore_ops tegra_ictlr_syscore_ops
= {
197 .suspend
= tegra_ictlr_suspend
,
198 .resume
= tegra_ictlr_resume
,
201 static void tegra_ictlr_syscore_init(void)
203 register_syscore_ops(&tegra_ictlr_syscore_ops
);
206 #define tegra_set_wake NULL
207 static inline void tegra_ictlr_syscore_init(void) {}
210 static struct irq_chip tegra_ictlr_chip
= {
212 .irq_eoi
= tegra_eoi
,
213 .irq_mask
= tegra_mask
,
214 .irq_unmask
= tegra_unmask
,
215 .irq_retrigger
= tegra_retrigger
,
216 .irq_set_wake
= tegra_set_wake
,
217 .irq_set_type
= irq_chip_set_type_parent
,
218 .flags
= IRQCHIP_MASK_ON_SUSPEND
,
220 .irq_set_affinity
= irq_chip_set_affinity_parent
,
224 static int tegra_ictlr_domain_translate(struct irq_domain
*d
,
225 struct irq_fwspec
*fwspec
,
226 unsigned long *hwirq
,
229 if (is_of_node(fwspec
->fwnode
)) {
230 if (fwspec
->param_count
!= 3)
233 /* No PPI should point to this domain */
234 if (fwspec
->param
[0] != 0)
237 *hwirq
= fwspec
->param
[1];
238 *type
= fwspec
->param
[2] & IRQ_TYPE_SENSE_MASK
;
245 static int tegra_ictlr_domain_alloc(struct irq_domain
*domain
,
247 unsigned int nr_irqs
, void *data
)
249 struct irq_fwspec
*fwspec
= data
;
250 struct irq_fwspec parent_fwspec
;
251 struct tegra_ictlr_info
*info
= domain
->host_data
;
252 irq_hw_number_t hwirq
;
255 if (fwspec
->param_count
!= 3)
256 return -EINVAL
; /* Not GIC compliant */
257 if (fwspec
->param
[0] != GIC_SPI
)
258 return -EINVAL
; /* No PPI should point to this domain */
260 hwirq
= fwspec
->param
[1];
261 if (hwirq
>= (num_ictlrs
* 32))
264 for (i
= 0; i
< nr_irqs
; i
++) {
265 int ictlr
= (hwirq
+ i
) / 32;
267 irq_domain_set_hwirq_and_chip(domain
, virq
+ i
, hwirq
+ i
,
269 (void __force
*)info
->base
[ictlr
]);
272 parent_fwspec
= *fwspec
;
273 parent_fwspec
.fwnode
= domain
->parent
->fwnode
;
274 return irq_domain_alloc_irqs_parent(domain
, virq
, nr_irqs
,
278 static const struct irq_domain_ops tegra_ictlr_domain_ops
= {
279 .translate
= tegra_ictlr_domain_translate
,
280 .alloc
= tegra_ictlr_domain_alloc
,
281 .free
= irq_domain_free_irqs_common
,
284 static int __init
tegra_ictlr_init(struct device_node
*node
,
285 struct device_node
*parent
)
287 struct irq_domain
*parent_domain
, *domain
;
288 const struct of_device_id
*match
;
289 const struct tegra_ictlr_soc
*soc
;
294 pr_err("%s: no parent, giving up\n", node
->full_name
);
298 parent_domain
= irq_find_host(parent
);
299 if (!parent_domain
) {
300 pr_err("%s: unable to obtain parent domain\n", node
->full_name
);
304 match
= of_match_node(ictlr_matches
, node
);
305 if (!match
) /* Should never happen... */
310 lic
= kzalloc(sizeof(*lic
), GFP_KERNEL
);
314 for (i
= 0; i
< TEGRA_MAX_NUM_ICTLRS
; i
++) {
317 base
= of_iomap(node
, i
);
323 /* Disable all interrupts */
324 writel_relaxed(~0UL, base
+ ICTLR_CPU_IER_CLR
);
325 /* All interrupts target IRQ */
326 writel_relaxed(0, base
+ ICTLR_CPU_IEP_CLASS
);
332 pr_err("%s: no valid regions, giving up\n", node
->full_name
);
337 WARN(num_ictlrs
!= soc
->num_ictlrs
,
338 "%s: Found %u interrupt controllers in DT; expected %u.\n",
339 node
->full_name
, num_ictlrs
, soc
->num_ictlrs
);
342 domain
= irq_domain_add_hierarchy(parent_domain
, 0, num_ictlrs
* 32,
343 node
, &tegra_ictlr_domain_ops
,
346 pr_err("%s: failed to allocated domain\n", node
->full_name
);
351 tegra_ictlr_syscore_init();
353 pr_info("%s: %d interrupts forwarded to %s\n",
354 node
->full_name
, num_ictlrs
* 32, parent
->full_name
);
359 for (i
= 0; i
< num_ictlrs
; i
++)
360 iounmap(lic
->base
[i
]);
366 IRQCHIP_DECLARE(tegra20_ictlr
, "nvidia,tegra20-ictlr", tegra_ictlr_init
);
367 IRQCHIP_DECLARE(tegra30_ictlr
, "nvidia,tegra30-ictlr", tegra_ictlr_init
);
368 IRQCHIP_DECLARE(tegra210_ictlr
, "nvidia,tegra210-ictlr", tegra_ictlr_init
);