xref: /linux/drivers/irqchip/irq-apple-aic.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
176cde263SHector Martin // SPDX-License-Identifier: GPL-2.0-or-later
276cde263SHector Martin /*
376cde263SHector Martin  * Copyright The Asahi Linux Contributors
476cde263SHector Martin  *
576cde263SHector Martin  * Based on irq-lpc32xx:
676cde263SHector Martin  *   Copyright 2015-2016 Vladimir Zapolskiy <vz@mleia.com>
776cde263SHector Martin  * Based on irq-bcm2836:
876cde263SHector Martin  *   Copyright 2015 Broadcom
976cde263SHector Martin  */
1076cde263SHector Martin 
1176cde263SHector Martin /*
1276cde263SHector Martin  * AIC is a fairly simple interrupt controller with the following features:
1376cde263SHector Martin  *
1476cde263SHector Martin  * - 896 level-triggered hardware IRQs
1576cde263SHector Martin  *   - Single mask bit per IRQ
1676cde263SHector Martin  *   - Per-IRQ affinity setting
1776cde263SHector Martin  *   - Automatic masking on event delivery (auto-ack)
1876cde263SHector Martin  *   - Software triggering (ORed with hw line)
1976cde263SHector Martin  * - 2 per-CPU IPIs (meant as "self" and "other", but they are
2076cde263SHector Martin  *   interchangeable if not symmetric)
2176cde263SHector Martin  * - Automatic prioritization (single event/ack register per CPU, lower IRQs =
2276cde263SHector Martin  *   higher priority)
2376cde263SHector Martin  * - Automatic masking on ack
2476cde263SHector Martin  * - Default "this CPU" register view and explicit per-CPU views
2576cde263SHector Martin  *
2676cde263SHector Martin  * In addition, this driver also handles FIQs, as these are routed to the same
272cf68211SHector Martin  * IRQ vector. These are used for Fast IPIs, the ARMv8 timer IRQs, and
2876cde263SHector Martin  * performance counters (TODO).
2976cde263SHector Martin  *
3076cde263SHector Martin  * Implementation notes:
3176cde263SHector Martin  *
3276cde263SHector Martin  * - This driver creates two IRQ domains, one for HW IRQs and internal FIQs,
3376cde263SHector Martin  *   and one for IPIs.
3476cde263SHector Martin  * - Since Linux needs more than 2 IPIs, we implement a software IRQ controller
3576cde263SHector Martin  *   and funnel all IPIs into one per-CPU IPI (the second "self" IPI is unused).
3676cde263SHector Martin  * - FIQ hwirq numbers are assigned after true hwirqs, and are per-cpu.
3776cde263SHector Martin  * - DT bindings use 3-cell form (like GIC):
3876cde263SHector Martin  *   - <0 nr flags> - hwirq #nr
3976cde263SHector Martin  *   - <1 nr flags> - FIQ #nr
4076cde263SHector Martin  *     - nr=0  Physical HV timer
4176cde263SHector Martin  *     - nr=1  Virtual HV timer
4276cde263SHector Martin  *     - nr=2  Physical guest timer
4376cde263SHector Martin  *     - nr=3  Virtual guest timer
4476cde263SHector Martin  */
4576cde263SHector Martin 
4676cde263SHector Martin #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4776cde263SHector Martin 
4876cde263SHector Martin #include <linux/bits.h>
4976cde263SHector Martin #include <linux/bitfield.h>
5076cde263SHector Martin #include <linux/cpuhotplug.h>
5176cde263SHector Martin #include <linux/io.h>
5276cde263SHector Martin #include <linux/irqchip.h>
53b6ca556cSMarc Zyngier #include <linux/irqchip/arm-vgic-info.h>
5476cde263SHector Martin #include <linux/irqdomain.h>
552cf68211SHector Martin #include <linux/jump_label.h>
5676cde263SHector Martin #include <linux/limits.h>
5776cde263SHector Martin #include <linux/of_address.h>
5876cde263SHector Martin #include <linux/slab.h>
5911db7410SMarc Zyngier #include <asm/apple_m1_pmu.h>
602cf68211SHector Martin #include <asm/cputype.h>
6176cde263SHector Martin #include <asm/exception.h>
6276cde263SHector Martin #include <asm/sysreg.h>
6376cde263SHector Martin #include <asm/virt.h>
6476cde263SHector Martin 
6576cde263SHector Martin #include <dt-bindings/interrupt-controller/apple-aic.h>
6676cde263SHector Martin 
6776cde263SHector Martin /*
68dc97fd6fSHector Martin  * AIC v1 registers (MMIO)
6976cde263SHector Martin  */
7076cde263SHector Martin 
7176cde263SHector Martin #define AIC_INFO		0x0004
727c841f5fSHector Martin #define AIC_INFO_NR_IRQ		GENMASK(15, 0)
7376cde263SHector Martin 
7476cde263SHector Martin #define AIC_CONFIG		0x0010
7576cde263SHector Martin 
7676cde263SHector Martin #define AIC_WHOAMI		0x2000
7776cde263SHector Martin #define AIC_EVENT		0x2004
78a801f0eeSHector Martin #define AIC_EVENT_DIE		GENMASK(31, 24)
79a801f0eeSHector Martin #define AIC_EVENT_TYPE		GENMASK(23, 16)
8076cde263SHector Martin #define AIC_EVENT_NUM		GENMASK(15, 0)
8176cde263SHector Martin 
827c841f5fSHector Martin #define AIC_EVENT_TYPE_FIQ	0 /* Software use */
837c841f5fSHector Martin #define AIC_EVENT_TYPE_IRQ	1
8476cde263SHector Martin #define AIC_EVENT_TYPE_IPI	4
8576cde263SHector Martin #define AIC_EVENT_IPI_OTHER	1
8676cde263SHector Martin #define AIC_EVENT_IPI_SELF	2
8776cde263SHector Martin 
8876cde263SHector Martin #define AIC_IPI_SEND		0x2008
8976cde263SHector Martin #define AIC_IPI_ACK		0x200c
9076cde263SHector Martin #define AIC_IPI_MASK_SET	0x2024
9176cde263SHector Martin #define AIC_IPI_MASK_CLR	0x2028
9276cde263SHector Martin 
9376cde263SHector Martin #define AIC_IPI_SEND_CPU(cpu)	BIT(cpu)
9476cde263SHector Martin 
9576cde263SHector Martin #define AIC_IPI_OTHER		BIT(0)
9676cde263SHector Martin #define AIC_IPI_SELF		BIT(31)
9776cde263SHector Martin 
9876cde263SHector Martin #define AIC_TARGET_CPU		0x3000
9976cde263SHector Martin 
10076cde263SHector Martin #define AIC_CPU_IPI_SET(cpu)	(0x5008 + ((cpu) << 7))
10176cde263SHector Martin #define AIC_CPU_IPI_CLR(cpu)	(0x500c + ((cpu) << 7))
10276cde263SHector Martin #define AIC_CPU_IPI_MASK_SET(cpu) (0x5024 + ((cpu) << 7))
10376cde263SHector Martin #define AIC_CPU_IPI_MASK_CLR(cpu) (0x5028 + ((cpu) << 7))
10476cde263SHector Martin 
105dc97fd6fSHector Martin #define AIC_MAX_IRQ		0x400
106dc97fd6fSHector Martin 
107768d4435SHector Martin /*
108768d4435SHector Martin  * AIC v2 registers (MMIO)
109768d4435SHector Martin  */
110768d4435SHector Martin 
111768d4435SHector Martin #define AIC2_VERSION		0x0000
112768d4435SHector Martin #define AIC2_VERSION_VER	GENMASK(7, 0)
113768d4435SHector Martin 
114768d4435SHector Martin #define AIC2_INFO1		0x0004
115768d4435SHector Martin #define AIC2_INFO1_NR_IRQ	GENMASK(15, 0)
116768d4435SHector Martin #define AIC2_INFO1_LAST_DIE	GENMASK(27, 24)
117768d4435SHector Martin 
118768d4435SHector Martin #define AIC2_INFO2		0x0008
119768d4435SHector Martin 
120768d4435SHector Martin #define AIC2_INFO3		0x000c
121768d4435SHector Martin #define AIC2_INFO3_MAX_IRQ	GENMASK(15, 0)
122768d4435SHector Martin #define AIC2_INFO3_MAX_DIE	GENMASK(27, 24)
123768d4435SHector Martin 
124768d4435SHector Martin #define AIC2_RESET		0x0010
125768d4435SHector Martin #define AIC2_RESET_RESET	BIT(0)
126768d4435SHector Martin 
127768d4435SHector Martin #define AIC2_CONFIG		0x0014
128768d4435SHector Martin #define AIC2_CONFIG_ENABLE	BIT(0)
129768d4435SHector Martin #define AIC2_CONFIG_PREFER_PCPU	BIT(28)
130768d4435SHector Martin 
131768d4435SHector Martin #define AIC2_TIMEOUT		0x0028
132768d4435SHector Martin #define AIC2_CLUSTER_PRIO	0x0030
133768d4435SHector Martin #define AIC2_DELAY_GROUPS	0x0100
134768d4435SHector Martin 
135768d4435SHector Martin #define AIC2_IRQ_CFG		0x2000
136768d4435SHector Martin 
137768d4435SHector Martin /*
138768d4435SHector Martin  * AIC2 registers are laid out like this, starting at AIC2_IRQ_CFG:
139768d4435SHector Martin  *
140768d4435SHector Martin  * Repeat for each die:
141768d4435SHector Martin  *   IRQ_CFG: u32 * MAX_IRQS
142768d4435SHector Martin  *   SW_SET: u32 * (MAX_IRQS / 32)
143768d4435SHector Martin  *   SW_CLR: u32 * (MAX_IRQS / 32)
144768d4435SHector Martin  *   MASK_SET: u32 * (MAX_IRQS / 32)
145768d4435SHector Martin  *   MASK_CLR: u32 * (MAX_IRQS / 32)
146768d4435SHector Martin  *   HW_STATE: u32 * (MAX_IRQS / 32)
147768d4435SHector Martin  *
148768d4435SHector Martin  * This is followed by a set of event registers, each 16K page aligned.
149768d4435SHector Martin  * The first one is the AP event register we will use. Unfortunately,
150768d4435SHector Martin  * the actual implemented die count is not specified anywhere in the
151768d4435SHector Martin  * capability registers, so we have to explicitly specify the event
152768d4435SHector Martin  * register as a second reg entry in the device tree to remain
153768d4435SHector Martin  * forward-compatible.
154768d4435SHector Martin  */
155768d4435SHector Martin 
156768d4435SHector Martin #define AIC2_IRQ_CFG_TARGET	GENMASK(3, 0)
157768d4435SHector Martin #define AIC2_IRQ_CFG_DELAY_IDX	GENMASK(7, 5)
158768d4435SHector Martin 
15976cde263SHector Martin #define MASK_REG(x)		(4 * ((x) >> 5))
16076cde263SHector Martin #define MASK_BIT(x)		BIT((x) & GENMASK(4, 0))
16176cde263SHector Martin 
16276cde263SHector Martin /*
16376cde263SHector Martin  * IMP-DEF sysregs that control FIQ sources
16476cde263SHector Martin  */
16576cde263SHector Martin 
16676cde263SHector Martin /* IPI request registers */
16776cde263SHector Martin #define SYS_IMP_APL_IPI_RR_LOCAL_EL1	sys_reg(3, 5, 15, 0, 0)
16876cde263SHector Martin #define SYS_IMP_APL_IPI_RR_GLOBAL_EL1	sys_reg(3, 5, 15, 0, 1)
16976cde263SHector Martin #define IPI_RR_CPU			GENMASK(7, 0)
17076cde263SHector Martin /* Cluster only used for the GLOBAL register */
17176cde263SHector Martin #define IPI_RR_CLUSTER			GENMASK(23, 16)
17276cde263SHector Martin #define IPI_RR_TYPE			GENMASK(29, 28)
17376cde263SHector Martin #define IPI_RR_IMMEDIATE		0
17476cde263SHector Martin #define IPI_RR_RETRACT			1
17576cde263SHector Martin #define IPI_RR_DEFERRED			2
17676cde263SHector Martin #define IPI_RR_NOWAKE			3
17776cde263SHector Martin 
17876cde263SHector Martin /* IPI status register */
17976cde263SHector Martin #define SYS_IMP_APL_IPI_SR_EL1		sys_reg(3, 5, 15, 1, 1)
18076cde263SHector Martin #define IPI_SR_PENDING			BIT(0)
18176cde263SHector Martin 
18276cde263SHector Martin /* Guest timer FIQ enable register */
18376cde263SHector Martin #define SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2	sys_reg(3, 5, 15, 1, 3)
18476cde263SHector Martin #define VM_TMR_FIQ_ENABLE_V		BIT(0)
18576cde263SHector Martin #define VM_TMR_FIQ_ENABLE_P		BIT(1)
18676cde263SHector Martin 
18776cde263SHector Martin /* Deferred IPI countdown register */
18876cde263SHector Martin #define SYS_IMP_APL_IPI_CR_EL1		sys_reg(3, 5, 15, 3, 1)
18976cde263SHector Martin 
19076cde263SHector Martin /* Uncore PMC control register */
19176cde263SHector Martin #define SYS_IMP_APL_UPMCR0_EL1		sys_reg(3, 7, 15, 0, 4)
19276cde263SHector Martin #define UPMCR0_IMODE			GENMASK(18, 16)
19376cde263SHector Martin #define UPMCR0_IMODE_OFF		0
19476cde263SHector Martin #define UPMCR0_IMODE_AIC		2
19576cde263SHector Martin #define UPMCR0_IMODE_HALT		3
19676cde263SHector Martin #define UPMCR0_IMODE_FIQ		4
19776cde263SHector Martin 
19876cde263SHector Martin /* Uncore PMC status register */
19976cde263SHector Martin #define SYS_IMP_APL_UPMSR_EL1		sys_reg(3, 7, 15, 6, 4)
20076cde263SHector Martin #define UPMSR_IACT			BIT(0)
20176cde263SHector Martin 
2022cf68211SHector Martin /* MPIDR fields */
2032cf68211SHector Martin #define MPIDR_CPU(x)			MPIDR_AFFINITY_LEVEL(x, 0)
2042cf68211SHector Martin #define MPIDR_CLUSTER(x)		MPIDR_AFFINITY_LEVEL(x, 1)
2052cf68211SHector Martin 
206a801f0eeSHector Martin #define AIC_IRQ_HWIRQ(die, irq)	(FIELD_PREP(AIC_EVENT_DIE, die) | \
207a801f0eeSHector Martin 				 FIELD_PREP(AIC_EVENT_TYPE, AIC_EVENT_TYPE_IRQ) | \
208a801f0eeSHector Martin 				 FIELD_PREP(AIC_EVENT_NUM, irq))
2097c841f5fSHector Martin #define AIC_FIQ_HWIRQ(x)	(FIELD_PREP(AIC_EVENT_TYPE, AIC_EVENT_TYPE_FIQ) | \
2107c841f5fSHector Martin 				 FIELD_PREP(AIC_EVENT_NUM, x))
2117c841f5fSHector Martin #define AIC_HWIRQ_IRQ(x)	FIELD_GET(AIC_EVENT_NUM, x)
212a801f0eeSHector Martin #define AIC_HWIRQ_DIE(x)	FIELD_GET(AIC_EVENT_DIE, x)
21376cde263SHector Martin #define AIC_NR_SWIPI		32
21476cde263SHector Martin 
21576cde263SHector Martin /*
21676cde263SHector Martin  * FIQ hwirq index definitions: FIQ sources use the DT binding defines
21776cde263SHector Martin  * directly, except that timers are special. At the irqchip level, the
21876cde263SHector Martin  * two timer types are represented by their access method: _EL0 registers
21976cde263SHector Martin  * or _EL02 registers. In the DT binding, the timers are represented
22076cde263SHector Martin  * by their purpose (HV or guest). This mapping is for when the kernel is
22176cde263SHector Martin  * running at EL2 (with VHE). When the kernel is running at EL1, the
22276cde263SHector Martin  * mapping differs and aic_irq_domain_translate() performs the remapping.
22376cde263SHector Martin  */
22413aad0c0SMarc Zyngier enum fiq_hwirq {
22513aad0c0SMarc Zyngier 	/* Must be ordered as in apple-aic.h */
22613aad0c0SMarc Zyngier 	AIC_TMR_EL0_PHYS	= AIC_TMR_HV_PHYS,
22713aad0c0SMarc Zyngier 	AIC_TMR_EL0_VIRT	= AIC_TMR_HV_VIRT,
22813aad0c0SMarc Zyngier 	AIC_TMR_EL02_PHYS	= AIC_TMR_GUEST_PHYS,
22913aad0c0SMarc Zyngier 	AIC_TMR_EL02_VIRT	= AIC_TMR_GUEST_VIRT,
23013aad0c0SMarc Zyngier 	AIC_CPU_PMU_Effi	= AIC_CPU_PMU_E,
23113aad0c0SMarc Zyngier 	AIC_CPU_PMU_Perf	= AIC_CPU_PMU_P,
23213aad0c0SMarc Zyngier 	/* No need for this to be discovered from DT */
23313aad0c0SMarc Zyngier 	AIC_VGIC_MI,
23413aad0c0SMarc Zyngier 	AIC_NR_FIQ
23513aad0c0SMarc Zyngier };
23676cde263SHector Martin 
237*59fc20baSKonrad Dybcio /* True if UNCORE/UNCORE2 and Sn_... IPI registers are present and used (A11+) */
2381357d2a6SWei Yongjun static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
239a845342eSNick Chan /* True if SYS_IMP_APL_IPI_RR_LOCAL_EL1 exists for local fast IPIs (M1+) */
240a845342eSNick Chan static DEFINE_STATIC_KEY_TRUE(use_local_fast_ipi);
2412cf68211SHector Martin 
2422cf68211SHector Martin struct aic_info {
2432cf68211SHector Martin 	int version;
2442cf68211SHector Martin 
245dc97fd6fSHector Martin 	/* Register offsets */
246dc97fd6fSHector Martin 	u32 event;
247dc97fd6fSHector Martin 	u32 target_cpu;
248768d4435SHector Martin 	u32 irq_cfg;
249dc97fd6fSHector Martin 	u32 sw_set;
250dc97fd6fSHector Martin 	u32 sw_clr;
251dc97fd6fSHector Martin 	u32 mask_set;
252dc97fd6fSHector Martin 	u32 mask_clr;
253dc97fd6fSHector Martin 
254a801f0eeSHector Martin 	u32 die_stride;
255a801f0eeSHector Martin 
2562cf68211SHector Martin 	/* Features */
2572cf68211SHector Martin 	bool fast_ipi;
258a845342eSNick Chan 	bool local_fast_ipi;
2592cf68211SHector Martin };
2602cf68211SHector Martin 
261d46b9965SKonrad Dybcio static const struct aic_info aic1_info __initconst = {
2622cf68211SHector Martin 	.version	= 1,
263dc97fd6fSHector Martin 
264dc97fd6fSHector Martin 	.event		= AIC_EVENT,
265dc97fd6fSHector Martin 	.target_cpu	= AIC_TARGET_CPU,
2662cf68211SHector Martin };
2672cf68211SHector Martin 
268d46b9965SKonrad Dybcio static const struct aic_info aic1_fipi_info __initconst = {
2692cf68211SHector Martin 	.version	= 1,
2702cf68211SHector Martin 
271dc97fd6fSHector Martin 	.event		= AIC_EVENT,
272dc97fd6fSHector Martin 	.target_cpu	= AIC_TARGET_CPU,
273dc97fd6fSHector Martin 
2742cf68211SHector Martin 	.fast_ipi	= true,
2752cf68211SHector Martin };
2762cf68211SHector Martin 
277a845342eSNick Chan static const struct aic_info aic1_local_fipi_info __initconst = {
278a845342eSNick Chan 	.version	= 1,
279a845342eSNick Chan 
280a845342eSNick Chan 	.event		= AIC_EVENT,
281a845342eSNick Chan 	.target_cpu	= AIC_TARGET_CPU,
282a845342eSNick Chan 
283a845342eSNick Chan 	.fast_ipi	= true,
284a845342eSNick Chan 	.local_fast_ipi = true,
285a845342eSNick Chan };
286a845342eSNick Chan 
287d46b9965SKonrad Dybcio static const struct aic_info aic2_info __initconst = {
288768d4435SHector Martin 	.version	= 2,
289768d4435SHector Martin 
290768d4435SHector Martin 	.irq_cfg	= AIC2_IRQ_CFG,
291768d4435SHector Martin 
292768d4435SHector Martin 	.fast_ipi	= true,
293a845342eSNick Chan 	.local_fast_ipi = true,
294768d4435SHector Martin };
295768d4435SHector Martin 
2962cf68211SHector Martin static const struct of_device_id aic_info_match[] = {
2972cf68211SHector Martin 	{
2982cf68211SHector Martin 		.compatible = "apple,t8103-aic",
299a845342eSNick Chan 		.data = &aic1_local_fipi_info,
300a845342eSNick Chan 	},
301a845342eSNick Chan 	{
302a845342eSNick Chan 		.compatible = "apple,t8015-aic",
3032cf68211SHector Martin 		.data = &aic1_fipi_info,
3042cf68211SHector Martin 	},
3052cf68211SHector Martin 	{
3062cf68211SHector Martin 		.compatible = "apple,aic",
3072cf68211SHector Martin 		.data = &aic1_info,
3082cf68211SHector Martin 	},
309768d4435SHector Martin 	{
310768d4435SHector Martin 		.compatible = "apple,aic2",
311768d4435SHector Martin 		.data = &aic2_info,
312768d4435SHector Martin 	},
3132cf68211SHector Martin 	{}
3142cf68211SHector Martin };
3152cf68211SHector Martin 
31676cde263SHector Martin struct aic_irq_chip {
31776cde263SHector Martin 	void __iomem *base;
318768d4435SHector Martin 	void __iomem *event;
31976cde263SHector Martin 	struct irq_domain *hw_domain;
320a5e88012SMarc Zyngier 	struct {
321a5e88012SMarc Zyngier 		cpumask_t aff;
322a5e88012SMarc Zyngier 	} *fiq_aff[AIC_NR_FIQ];
323dc97fd6fSHector Martin 
3247c841f5fSHector Martin 	int nr_irq;
325dc97fd6fSHector Martin 	int max_irq;
326a801f0eeSHector Martin 	int nr_die;
327a801f0eeSHector Martin 	int max_die;
3282cf68211SHector Martin 
3292cf68211SHector Martin 	struct aic_info info;
33076cde263SHector Martin };
33176cde263SHector Martin 
33276cde263SHector Martin static DEFINE_PER_CPU(uint32_t, aic_fiq_unmasked);
33376cde263SHector Martin 
33476cde263SHector Martin static struct aic_irq_chip *aic_irqc;
33576cde263SHector Martin 
33676cde263SHector Martin static void aic_handle_ipi(struct pt_regs *regs);
33776cde263SHector Martin 
aic_ic_read(struct aic_irq_chip * ic,u32 reg)33876cde263SHector Martin static u32 aic_ic_read(struct aic_irq_chip *ic, u32 reg)
33976cde263SHector Martin {
34076cde263SHector Martin 	return readl_relaxed(ic->base + reg);
34176cde263SHector Martin }
34276cde263SHector Martin 
aic_ic_write(struct aic_irq_chip * ic,u32 reg,u32 val)34376cde263SHector Martin static void aic_ic_write(struct aic_irq_chip *ic, u32 reg, u32 val)
34476cde263SHector Martin {
34576cde263SHector Martin 	writel_relaxed(val, ic->base + reg);
34676cde263SHector Martin }
34776cde263SHector Martin 
34876cde263SHector Martin /*
34976cde263SHector Martin  * IRQ irqchip
35076cde263SHector Martin  */
35176cde263SHector Martin 
aic_irq_mask(struct irq_data * d)35276cde263SHector Martin static void aic_irq_mask(struct irq_data *d)
35376cde263SHector Martin {
3547c841f5fSHector Martin 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
35576cde263SHector Martin 	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
35676cde263SHector Martin 
357a801f0eeSHector Martin 	u32 off = AIC_HWIRQ_DIE(hwirq) * ic->info.die_stride;
3587c841f5fSHector Martin 	u32 irq = AIC_HWIRQ_IRQ(hwirq);
3597c841f5fSHector Martin 
360a801f0eeSHector Martin 	aic_ic_write(ic, ic->info.mask_set + off + MASK_REG(irq), MASK_BIT(irq));
36176cde263SHector Martin }
36276cde263SHector Martin 
aic_irq_unmask(struct irq_data * d)36376cde263SHector Martin static void aic_irq_unmask(struct irq_data *d)
36476cde263SHector Martin {
3657c841f5fSHector Martin 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
36676cde263SHector Martin 	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
36776cde263SHector Martin 
368a801f0eeSHector Martin 	u32 off = AIC_HWIRQ_DIE(hwirq) * ic->info.die_stride;
3697c841f5fSHector Martin 	u32 irq = AIC_HWIRQ_IRQ(hwirq);
3707c841f5fSHector Martin 
371a801f0eeSHector Martin 	aic_ic_write(ic, ic->info.mask_clr + off + MASK_REG(irq), MASK_BIT(irq));
37276cde263SHector Martin }
37376cde263SHector Martin 
aic_irq_eoi(struct irq_data * d)37476cde263SHector Martin static void aic_irq_eoi(struct irq_data *d)
37576cde263SHector Martin {
37676cde263SHector Martin 	/*
37776cde263SHector Martin 	 * Reading the interrupt reason automatically acknowledges and masks
37876cde263SHector Martin 	 * the IRQ, so we just unmask it here if needed.
37976cde263SHector Martin 	 */
38060a1cd10SSven Peter 	if (!irqd_irq_masked(d))
38176cde263SHector Martin 		aic_irq_unmask(d);
38276cde263SHector Martin }
38376cde263SHector Martin 
aic_handle_irq(struct pt_regs * regs)38476cde263SHector Martin static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
38576cde263SHector Martin {
38676cde263SHector Martin 	struct aic_irq_chip *ic = aic_irqc;
38776cde263SHector Martin 	u32 event, type, irq;
38876cde263SHector Martin 
38976cde263SHector Martin 	do {
39076cde263SHector Martin 		/*
39176cde263SHector Martin 		 * We cannot use a relaxed read here, as reads from DMA buffers
39276cde263SHector Martin 		 * need to be ordered after the IRQ fires.
39376cde263SHector Martin 		 */
394768d4435SHector Martin 		event = readl(ic->event + ic->info.event);
39576cde263SHector Martin 		type = FIELD_GET(AIC_EVENT_TYPE, event);
39676cde263SHector Martin 		irq = FIELD_GET(AIC_EVENT_NUM, event);
39776cde263SHector Martin 
3987c841f5fSHector Martin 		if (type == AIC_EVENT_TYPE_IRQ)
3997c841f5fSHector Martin 			generic_handle_domain_irq(aic_irqc->hw_domain, event);
40076cde263SHector Martin 		else if (type == AIC_EVENT_TYPE_IPI && irq == 1)
40176cde263SHector Martin 			aic_handle_ipi(regs);
40276cde263SHector Martin 		else if (event != 0)
40376cde263SHector Martin 			pr_err_ratelimited("Unknown IRQ event %d, %d\n", type, irq);
40476cde263SHector Martin 	} while (event);
40576cde263SHector Martin 
40676cde263SHector Martin 	/*
40776cde263SHector Martin 	 * vGIC maintenance interrupts end up here too, so we need to check
40813aad0c0SMarc Zyngier 	 * for them separately. It should however only trigger when NV is
40913aad0c0SMarc Zyngier 	 * in use, and be cleared when coming back from the handler.
41076cde263SHector Martin 	 */
41113aad0c0SMarc Zyngier 	if (is_kernel_in_hyp_mode() &&
41213aad0c0SMarc Zyngier 	    (read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
41376cde263SHector Martin 	    read_sysreg_s(SYS_ICH_MISR_EL2) != 0) {
41413aad0c0SMarc Zyngier 		generic_handle_domain_irq(aic_irqc->hw_domain,
41513aad0c0SMarc Zyngier 					  AIC_FIQ_HWIRQ(AIC_VGIC_MI));
41613aad0c0SMarc Zyngier 
41713aad0c0SMarc Zyngier 		if (unlikely((read_sysreg_s(SYS_ICH_HCR_EL2) & ICH_HCR_EN) &&
41813aad0c0SMarc Zyngier 			     read_sysreg_s(SYS_ICH_MISR_EL2))) {
41976cde263SHector Martin 			pr_err_ratelimited("vGIC IRQ fired and not handled by KVM, disabling.\n");
42076cde263SHector Martin 			sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
42176cde263SHector Martin 		}
42276cde263SHector Martin 	}
42313aad0c0SMarc Zyngier }
42476cde263SHector Martin 
aic_irq_set_affinity(struct irq_data * d,const struct cpumask * mask_val,bool force)42576cde263SHector Martin static int aic_irq_set_affinity(struct irq_data *d,
42676cde263SHector Martin 				const struct cpumask *mask_val, bool force)
42776cde263SHector Martin {
42876cde263SHector Martin 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
42976cde263SHector Martin 	struct aic_irq_chip *ic = irq_data_get_irq_chip_data(d);
43076cde263SHector Martin 	int cpu;
43176cde263SHector Martin 
432dc97fd6fSHector Martin 	BUG_ON(!ic->info.target_cpu);
433dc97fd6fSHector Martin 
43476cde263SHector Martin 	if (force)
43576cde263SHector Martin 		cpu = cpumask_first(mask_val);
43676cde263SHector Martin 	else
43776cde263SHector Martin 		cpu = cpumask_any_and(mask_val, cpu_online_mask);
43876cde263SHector Martin 
439dc97fd6fSHector Martin 	aic_ic_write(ic, ic->info.target_cpu + AIC_HWIRQ_IRQ(hwirq) * 4, BIT(cpu));
44076cde263SHector Martin 	irq_data_update_effective_affinity(d, cpumask_of(cpu));
44176cde263SHector Martin 
44276cde263SHector Martin 	return IRQ_SET_MASK_OK;
44376cde263SHector Martin }
44476cde263SHector Martin 
aic_irq_set_type(struct irq_data * d,unsigned int type)44576cde263SHector Martin static int aic_irq_set_type(struct irq_data *d, unsigned int type)
44676cde263SHector Martin {
44776cde263SHector Martin 	/*
44876cde263SHector Martin 	 * Some IRQs (e.g. MSIs) implicitly have edge semantics, and we don't
44976cde263SHector Martin 	 * have a way to find out the type of any given IRQ, so just allow both.
45076cde263SHector Martin 	 */
45176cde263SHector Martin 	return (type == IRQ_TYPE_LEVEL_HIGH || type == IRQ_TYPE_EDGE_RISING) ? 0 : -EINVAL;
45276cde263SHector Martin }
45376cde263SHector Martin 
45476cde263SHector Martin static struct irq_chip aic_chip = {
45576cde263SHector Martin 	.name = "AIC",
45676cde263SHector Martin 	.irq_mask = aic_irq_mask,
45776cde263SHector Martin 	.irq_unmask = aic_irq_unmask,
45876cde263SHector Martin 	.irq_eoi = aic_irq_eoi,
45976cde263SHector Martin 	.irq_set_affinity = aic_irq_set_affinity,
46076cde263SHector Martin 	.irq_set_type = aic_irq_set_type,
46176cde263SHector Martin };
46276cde263SHector Martin 
463768d4435SHector Martin static struct irq_chip aic2_chip = {
464768d4435SHector Martin 	.name = "AIC2",
465768d4435SHector Martin 	.irq_mask = aic_irq_mask,
466768d4435SHector Martin 	.irq_unmask = aic_irq_unmask,
467768d4435SHector Martin 	.irq_eoi = aic_irq_eoi,
468768d4435SHector Martin 	.irq_set_type = aic_irq_set_type,
469768d4435SHector Martin };
470768d4435SHector Martin 
47176cde263SHector Martin /*
47276cde263SHector Martin  * FIQ irqchip
47376cde263SHector Martin  */
47476cde263SHector Martin 
aic_fiq_get_idx(struct irq_data * d)47576cde263SHector Martin static unsigned long aic_fiq_get_idx(struct irq_data *d)
47676cde263SHector Martin {
4777c841f5fSHector Martin 	return AIC_HWIRQ_IRQ(irqd_to_hwirq(d));
47876cde263SHector Martin }
47976cde263SHector Martin 
aic_fiq_set_mask(struct irq_data * d)48076cde263SHector Martin static void aic_fiq_set_mask(struct irq_data *d)
48176cde263SHector Martin {
48276cde263SHector Martin 	/* Only the guest timers have real mask bits, unfortunately. */
48376cde263SHector Martin 	switch (aic_fiq_get_idx(d)) {
48476cde263SHector Martin 	case AIC_TMR_EL02_PHYS:
48576cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENABLE_P, 0);
48676cde263SHector Martin 		isb();
48776cde263SHector Martin 		break;
48876cde263SHector Martin 	case AIC_TMR_EL02_VIRT:
48976cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENABLE_V, 0);
49076cde263SHector Martin 		isb();
49176cde263SHector Martin 		break;
49276cde263SHector Martin 	default:
49376cde263SHector Martin 		break;
49476cde263SHector Martin 	}
49576cde263SHector Martin }
49676cde263SHector Martin 
aic_fiq_clear_mask(struct irq_data * d)49776cde263SHector Martin static void aic_fiq_clear_mask(struct irq_data *d)
49876cde263SHector Martin {
49976cde263SHector Martin 	switch (aic_fiq_get_idx(d)) {
50076cde263SHector Martin 	case AIC_TMR_EL02_PHYS:
50176cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, 0, VM_TMR_FIQ_ENABLE_P);
50276cde263SHector Martin 		isb();
50376cde263SHector Martin 		break;
50476cde263SHector Martin 	case AIC_TMR_EL02_VIRT:
50576cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, 0, VM_TMR_FIQ_ENABLE_V);
50676cde263SHector Martin 		isb();
50776cde263SHector Martin 		break;
50876cde263SHector Martin 	default:
50976cde263SHector Martin 		break;
51076cde263SHector Martin 	}
51176cde263SHector Martin }
51276cde263SHector Martin 
aic_fiq_mask(struct irq_data * d)51376cde263SHector Martin static void aic_fiq_mask(struct irq_data *d)
51476cde263SHector Martin {
51576cde263SHector Martin 	aic_fiq_set_mask(d);
51676cde263SHector Martin 	__this_cpu_and(aic_fiq_unmasked, ~BIT(aic_fiq_get_idx(d)));
51776cde263SHector Martin }
51876cde263SHector Martin 
aic_fiq_unmask(struct irq_data * d)51976cde263SHector Martin static void aic_fiq_unmask(struct irq_data *d)
52076cde263SHector Martin {
52176cde263SHector Martin 	aic_fiq_clear_mask(d);
52276cde263SHector Martin 	__this_cpu_or(aic_fiq_unmasked, BIT(aic_fiq_get_idx(d)));
52376cde263SHector Martin }
52476cde263SHector Martin 
aic_fiq_eoi(struct irq_data * d)52576cde263SHector Martin static void aic_fiq_eoi(struct irq_data *d)
52676cde263SHector Martin {
52776cde263SHector Martin 	/* We mask to ack (where we can), so we need to unmask at EOI. */
52876cde263SHector Martin 	if (__this_cpu_read(aic_fiq_unmasked) & BIT(aic_fiq_get_idx(d)))
52976cde263SHector Martin 		aic_fiq_clear_mask(d);
53076cde263SHector Martin }
53176cde263SHector Martin 
53276cde263SHector Martin #define TIMER_FIRING(x)                                                        \
53376cde263SHector Martin 	(((x) & (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_MASK |            \
53476cde263SHector Martin 		 ARCH_TIMER_CTRL_IT_STAT)) ==                                  \
53576cde263SHector Martin 	 (ARCH_TIMER_CTRL_ENABLE | ARCH_TIMER_CTRL_IT_STAT))
53676cde263SHector Martin 
aic_handle_fiq(struct pt_regs * regs)53776cde263SHector Martin static void __exception_irq_entry aic_handle_fiq(struct pt_regs *regs)
53876cde263SHector Martin {
53976cde263SHector Martin 	/*
54076cde263SHector Martin 	 * It would be really nice if we had a system register that lets us get
54176cde263SHector Martin 	 * the FIQ source state without having to peek down into sources...
54276cde263SHector Martin 	 * but such a register does not seem to exist.
54376cde263SHector Martin 	 *
54476cde263SHector Martin 	 * So, we have these potential sources to test for:
54576cde263SHector Martin 	 *  - Fast IPIs (not yet used)
54676cde263SHector Martin 	 *  - The 4 timers (CNTP, CNTV for each of HV and guest)
54776cde263SHector Martin 	 *  - Per-core PMCs (not yet supported)
54876cde263SHector Martin 	 *  - Per-cluster uncore PMCs (not yet supported)
54976cde263SHector Martin 	 *
55076cde263SHector Martin 	 * Since not dealing with any of these results in a FIQ storm,
55176cde263SHector Martin 	 * we check for everything here, even things we don't support yet.
55276cde263SHector Martin 	 */
55376cde263SHector Martin 
554*59fc20baSKonrad Dybcio 	if (static_branch_likely(&use_fast_ipi) &&
555*59fc20baSKonrad Dybcio 	    (read_sysreg_s(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING))
5562cf68211SHector Martin 		aic_handle_ipi(regs);
55776cde263SHector Martin 
55876cde263SHector Martin 	if (TIMER_FIRING(read_sysreg(cntp_ctl_el0)))
5590953fb26SMark Rutland 		generic_handle_domain_irq(aic_irqc->hw_domain,
5607c841f5fSHector Martin 					  AIC_FIQ_HWIRQ(AIC_TMR_EL0_PHYS));
56176cde263SHector Martin 
56276cde263SHector Martin 	if (TIMER_FIRING(read_sysreg(cntv_ctl_el0)))
5630953fb26SMark Rutland 		generic_handle_domain_irq(aic_irqc->hw_domain,
5647c841f5fSHector Martin 					  AIC_FIQ_HWIRQ(AIC_TMR_EL0_VIRT));
56576cde263SHector Martin 
56676cde263SHector Martin 	if (is_kernel_in_hyp_mode()) {
56776cde263SHector Martin 		uint64_t enabled = read_sysreg_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2);
56876cde263SHector Martin 
56976cde263SHector Martin 		if ((enabled & VM_TMR_FIQ_ENABLE_P) &&
57076cde263SHector Martin 		    TIMER_FIRING(read_sysreg_s(SYS_CNTP_CTL_EL02)))
5710953fb26SMark Rutland 			generic_handle_domain_irq(aic_irqc->hw_domain,
5727c841f5fSHector Martin 						  AIC_FIQ_HWIRQ(AIC_TMR_EL02_PHYS));
57376cde263SHector Martin 
57476cde263SHector Martin 		if ((enabled & VM_TMR_FIQ_ENABLE_V) &&
57576cde263SHector Martin 		    TIMER_FIRING(read_sysreg_s(SYS_CNTV_CTL_EL02)))
5760953fb26SMark Rutland 			generic_handle_domain_irq(aic_irqc->hw_domain,
5777c841f5fSHector Martin 						  AIC_FIQ_HWIRQ(AIC_TMR_EL02_VIRT));
57876cde263SHector Martin 	}
57976cde263SHector Martin 
580c7708816SMarc Zyngier 	if (read_sysreg_s(SYS_IMP_APL_PMCR0_EL1) & PMCR0_IACT) {
581c7708816SMarc Zyngier 		int irq;
582c7708816SMarc Zyngier 		if (cpumask_test_cpu(smp_processor_id(),
583c7708816SMarc Zyngier 				     &aic_irqc->fiq_aff[AIC_CPU_PMU_P]->aff))
584c7708816SMarc Zyngier 			irq = AIC_CPU_PMU_P;
585c7708816SMarc Zyngier 		else
586c7708816SMarc Zyngier 			irq = AIC_CPU_PMU_E;
587c7708816SMarc Zyngier 		generic_handle_domain_irq(aic_irqc->hw_domain,
58889ea5be1SMarc Zyngier 					  AIC_FIQ_HWIRQ(irq));
58976cde263SHector Martin 	}
59076cde263SHector Martin 
591*59fc20baSKonrad Dybcio 	if (static_branch_likely(&use_fast_ipi) &&
592*59fc20baSKonrad Dybcio 	    (FIELD_GET(UPMCR0_IMODE, read_sysreg_s(SYS_IMP_APL_UPMCR0_EL1)) == UPMCR0_IMODE_FIQ) &&
59376cde263SHector Martin 	    (read_sysreg_s(SYS_IMP_APL_UPMSR_EL1) & UPMSR_IACT)) {
59476cde263SHector Martin 		/* Same story with uncore PMCs */
59576cde263SHector Martin 		pr_err_ratelimited("Uncore PMC FIQ fired. Masking.\n");
59676cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE,
59776cde263SHector Martin 				   FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF));
59876cde263SHector Martin 	}
59976cde263SHector Martin }
60076cde263SHector Martin 
aic_fiq_set_type(struct irq_data * d,unsigned int type)60176cde263SHector Martin static int aic_fiq_set_type(struct irq_data *d, unsigned int type)
60276cde263SHector Martin {
60376cde263SHector Martin 	return (type == IRQ_TYPE_LEVEL_HIGH) ? 0 : -EINVAL;
60476cde263SHector Martin }
60576cde263SHector Martin 
60676cde263SHector Martin static struct irq_chip fiq_chip = {
60776cde263SHector Martin 	.name = "AIC-FIQ",
60876cde263SHector Martin 	.irq_mask = aic_fiq_mask,
60976cde263SHector Martin 	.irq_unmask = aic_fiq_unmask,
61076cde263SHector Martin 	.irq_ack = aic_fiq_set_mask,
61176cde263SHector Martin 	.irq_eoi = aic_fiq_eoi,
61276cde263SHector Martin 	.irq_set_type = aic_fiq_set_type,
61376cde263SHector Martin };
61476cde263SHector Martin 
61576cde263SHector Martin /*
61676cde263SHector Martin  * Main IRQ domain
61776cde263SHector Martin  */
61876cde263SHector Martin 
aic_irq_domain_map(struct irq_domain * id,unsigned int irq,irq_hw_number_t hw)61976cde263SHector Martin static int aic_irq_domain_map(struct irq_domain *id, unsigned int irq,
62076cde263SHector Martin 			      irq_hw_number_t hw)
62176cde263SHector Martin {
62276cde263SHector Martin 	struct aic_irq_chip *ic = id->host_data;
6237c841f5fSHector Martin 	u32 type = FIELD_GET(AIC_EVENT_TYPE, hw);
624768d4435SHector Martin 	struct irq_chip *chip = &aic_chip;
62576cde263SHector Martin 
626768d4435SHector Martin 	if (ic->info.version == 2)
627768d4435SHector Martin 		chip = &aic2_chip;
62876cde263SHector Martin 
6297c841f5fSHector Martin 	if (type == AIC_EVENT_TYPE_IRQ) {
630768d4435SHector Martin 		irq_domain_set_info(id, irq, hw, chip, id->host_data,
63176cde263SHector Martin 				    handle_fasteoi_irq, NULL, NULL);
63276cde263SHector Martin 		irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(irq)));
63376cde263SHector Martin 	} else {
63489ea5be1SMarc Zyngier 		int fiq = FIELD_GET(AIC_EVENT_NUM, hw);
635c7708816SMarc Zyngier 
636c7708816SMarc Zyngier 		switch (fiq) {
637c7708816SMarc Zyngier 		case AIC_CPU_PMU_P:
638c7708816SMarc Zyngier 		case AIC_CPU_PMU_E:
639c7708816SMarc Zyngier 			irq_set_percpu_devid_partition(irq, &ic->fiq_aff[fiq]->aff);
640c7708816SMarc Zyngier 			break;
641c7708816SMarc Zyngier 		default:
64276cde263SHector Martin 			irq_set_percpu_devid(irq);
643c7708816SMarc Zyngier 			break;
644c7708816SMarc Zyngier 		}
645c7708816SMarc Zyngier 
64676cde263SHector Martin 		irq_domain_set_info(id, irq, hw, &fiq_chip, id->host_data,
64776cde263SHector Martin 				    handle_percpu_devid_irq, NULL, NULL);
64876cde263SHector Martin 	}
64976cde263SHector Martin 
65076cde263SHector Martin 	return 0;
65176cde263SHector Martin }
65276cde263SHector Martin 
aic_irq_domain_translate(struct irq_domain * id,struct irq_fwspec * fwspec,unsigned long * hwirq,unsigned int * type)65376cde263SHector Martin static int aic_irq_domain_translate(struct irq_domain *id,
65476cde263SHector Martin 				    struct irq_fwspec *fwspec,
65576cde263SHector Martin 				    unsigned long *hwirq,
65676cde263SHector Martin 				    unsigned int *type)
65776cde263SHector Martin {
65876cde263SHector Martin 	struct aic_irq_chip *ic = id->host_data;
659a801f0eeSHector Martin 	u32 *args;
660a801f0eeSHector Martin 	u32 die = 0;
66176cde263SHector Martin 
662a801f0eeSHector Martin 	if (fwspec->param_count < 3 || fwspec->param_count > 4 ||
663a801f0eeSHector Martin 	    !is_of_node(fwspec->fwnode))
66476cde263SHector Martin 		return -EINVAL;
66576cde263SHector Martin 
666a801f0eeSHector Martin 	args = &fwspec->param[1];
667a801f0eeSHector Martin 
668a801f0eeSHector Martin 	if (fwspec->param_count == 4) {
669a801f0eeSHector Martin 		die = args[0];
670a801f0eeSHector Martin 		args++;
671a801f0eeSHector Martin 	}
672a801f0eeSHector Martin 
67376cde263SHector Martin 	switch (fwspec->param[0]) {
67476cde263SHector Martin 	case AIC_IRQ:
675a801f0eeSHector Martin 		if (die >= ic->nr_die)
67676cde263SHector Martin 			return -EINVAL;
677a801f0eeSHector Martin 		if (args[0] >= ic->nr_irq)
678a801f0eeSHector Martin 			return -EINVAL;
679a801f0eeSHector Martin 		*hwirq = AIC_IRQ_HWIRQ(die, args[0]);
68076cde263SHector Martin 		break;
68176cde263SHector Martin 	case AIC_FIQ:
682a801f0eeSHector Martin 		if (die != 0)
68376cde263SHector Martin 			return -EINVAL;
684a801f0eeSHector Martin 		if (args[0] >= AIC_NR_FIQ)
685a801f0eeSHector Martin 			return -EINVAL;
686a801f0eeSHector Martin 		*hwirq = AIC_FIQ_HWIRQ(args[0]);
68776cde263SHector Martin 
68876cde263SHector Martin 		/*
68976cde263SHector Martin 		 * In EL1 the non-redirected registers are the guest's,
69076cde263SHector Martin 		 * not EL2's, so remap the hwirqs to match.
69176cde263SHector Martin 		 */
69276cde263SHector Martin 		if (!is_kernel_in_hyp_mode()) {
693a801f0eeSHector Martin 			switch (args[0]) {
69476cde263SHector Martin 			case AIC_TMR_GUEST_PHYS:
6957c841f5fSHector Martin 				*hwirq = AIC_FIQ_HWIRQ(AIC_TMR_EL0_PHYS);
69676cde263SHector Martin 				break;
69776cde263SHector Martin 			case AIC_TMR_GUEST_VIRT:
6987c841f5fSHector Martin 				*hwirq = AIC_FIQ_HWIRQ(AIC_TMR_EL0_VIRT);
69976cde263SHector Martin 				break;
70076cde263SHector Martin 			case AIC_TMR_HV_PHYS:
70176cde263SHector Martin 			case AIC_TMR_HV_VIRT:
70276cde263SHector Martin 				return -ENOENT;
70376cde263SHector Martin 			default:
70476cde263SHector Martin 				break;
70576cde263SHector Martin 			}
70676cde263SHector Martin 		}
70776cde263SHector Martin 		break;
70876cde263SHector Martin 	default:
70976cde263SHector Martin 		return -EINVAL;
71076cde263SHector Martin 	}
71176cde263SHector Martin 
712a801f0eeSHector Martin 	*type = args[1] & IRQ_TYPE_SENSE_MASK;
71376cde263SHector Martin 
71476cde263SHector Martin 	return 0;
71576cde263SHector Martin }
71676cde263SHector Martin 
aic_irq_domain_alloc(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs,void * arg)71776cde263SHector Martin static int aic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
71876cde263SHector Martin 				unsigned int nr_irqs, void *arg)
71976cde263SHector Martin {
72076cde263SHector Martin 	unsigned int type = IRQ_TYPE_NONE;
72176cde263SHector Martin 	struct irq_fwspec *fwspec = arg;
72276cde263SHector Martin 	irq_hw_number_t hwirq;
72376cde263SHector Martin 	int i, ret;
72476cde263SHector Martin 
72576cde263SHector Martin 	ret = aic_irq_domain_translate(domain, fwspec, &hwirq, &type);
72676cde263SHector Martin 	if (ret)
72776cde263SHector Martin 		return ret;
72876cde263SHector Martin 
72976cde263SHector Martin 	for (i = 0; i < nr_irqs; i++) {
73076cde263SHector Martin 		ret = aic_irq_domain_map(domain, virq + i, hwirq + i);
73176cde263SHector Martin 		if (ret)
73276cde263SHector Martin 			return ret;
73376cde263SHector Martin 	}
73476cde263SHector Martin 
73576cde263SHector Martin 	return 0;
73676cde263SHector Martin }
73776cde263SHector Martin 
aic_irq_domain_free(struct irq_domain * domain,unsigned int virq,unsigned int nr_irqs)73876cde263SHector Martin static void aic_irq_domain_free(struct irq_domain *domain, unsigned int virq,
73976cde263SHector Martin 				unsigned int nr_irqs)
74076cde263SHector Martin {
74176cde263SHector Martin 	int i;
74276cde263SHector Martin 
74376cde263SHector Martin 	for (i = 0; i < nr_irqs; i++) {
74476cde263SHector Martin 		struct irq_data *d = irq_domain_get_irq_data(domain, virq + i);
74576cde263SHector Martin 
74676cde263SHector Martin 		irq_set_handler(virq + i, NULL);
74776cde263SHector Martin 		irq_domain_reset_irq_data(d);
74876cde263SHector Martin 	}
74976cde263SHector Martin }
75076cde263SHector Martin 
75176cde263SHector Martin static const struct irq_domain_ops aic_irq_domain_ops = {
75276cde263SHector Martin 	.translate	= aic_irq_domain_translate,
75376cde263SHector Martin 	.alloc		= aic_irq_domain_alloc,
75476cde263SHector Martin 	.free		= aic_irq_domain_free,
75576cde263SHector Martin };
75676cde263SHector Martin 
75776cde263SHector Martin /*
75876cde263SHector Martin  * IPI irqchip
75976cde263SHector Martin  */
76076cde263SHector Martin 
aic_ipi_send_fast(int cpu)7612cf68211SHector Martin static void aic_ipi_send_fast(int cpu)
7622cf68211SHector Martin {
7632cf68211SHector Martin 	u64 mpidr = cpu_logical_map(cpu);
7642cf68211SHector Martin 	u64 my_mpidr = read_cpuid_mpidr();
7652cf68211SHector Martin 	u64 cluster = MPIDR_CLUSTER(mpidr);
7662cf68211SHector Martin 	u64 idx = MPIDR_CPU(mpidr);
7672cf68211SHector Martin 
768a845342eSNick Chan 	if (static_branch_likely(&use_local_fast_ipi) && MPIDR_CLUSTER(my_mpidr) == cluster) {
769a845342eSNick Chan 		write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx), SYS_IMP_APL_IPI_RR_LOCAL_EL1);
770a845342eSNick Chan 	} else {
7712cf68211SHector Martin 		write_sysreg_s(FIELD_PREP(IPI_RR_CPU, idx) | FIELD_PREP(IPI_RR_CLUSTER, cluster),
7722cf68211SHector Martin 			       SYS_IMP_APL_IPI_RR_GLOBAL_EL1);
773a845342eSNick Chan 	}
7742cf68211SHector Martin 	isb();
7752cf68211SHector Martin }
7762cf68211SHector Martin 
aic_handle_ipi(struct pt_regs * regs)77776cde263SHector Martin static void aic_handle_ipi(struct pt_regs *regs)
77876cde263SHector Martin {
77976cde263SHector Martin 	/*
78076cde263SHector Martin 	 * Ack the IPI. We need to order this after the AIC event read, but
78176cde263SHector Martin 	 * that is enforced by normal MMIO ordering guarantees.
7822cf68211SHector Martin 	 *
7832cf68211SHector Martin 	 * For the Fast IPI case, this needs to be ordered before the vIPI
7842cf68211SHector Martin 	 * handling below, so we need to isb();
78576cde263SHector Martin 	 */
7862cf68211SHector Martin 	if (static_branch_likely(&use_fast_ipi)) {
7872cf68211SHector Martin 		write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1);
7882cf68211SHector Martin 		isb();
7892cf68211SHector Martin 	} else {
79076cde263SHector Martin 		aic_ic_write(aic_irqc, AIC_IPI_ACK, AIC_IPI_OTHER);
7912cf68211SHector Martin 	}
79276cde263SHector Martin 
793c19f8971SMarc Zyngier 	ipi_mux_process();
79476cde263SHector Martin 
79576cde263SHector Martin 	/*
79676cde263SHector Martin 	 * No ordering needed here; at worst this just changes the timing of
79776cde263SHector Martin 	 * when the next IPI will be delivered.
79876cde263SHector Martin 	 */
7992cf68211SHector Martin 	if (!static_branch_likely(&use_fast_ipi))
80076cde263SHector Martin 		aic_ic_write(aic_irqc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
80176cde263SHector Martin }
80276cde263SHector Martin 
aic_ipi_send_single(unsigned int cpu)803c19f8971SMarc Zyngier static void aic_ipi_send_single(unsigned int cpu)
80476cde263SHector Martin {
805c19f8971SMarc Zyngier 	if (static_branch_likely(&use_fast_ipi))
806c19f8971SMarc Zyngier 		aic_ipi_send_fast(cpu);
807c19f8971SMarc Zyngier 	else
808c19f8971SMarc Zyngier 		aic_ic_write(aic_irqc, AIC_IPI_SEND, AIC_IPI_SEND_CPU(cpu));
80976cde263SHector Martin }
81076cde263SHector Martin 
aic_init_smp(struct aic_irq_chip * irqc,struct device_node * node)8113d9e575fSDonghyeok Kim static int __init aic_init_smp(struct aic_irq_chip *irqc, struct device_node *node)
81276cde263SHector Martin {
81376cde263SHector Martin 	int base_ipi;
81476cde263SHector Martin 
815c19f8971SMarc Zyngier 	base_ipi = ipi_mux_create(AIC_NR_SWIPI, aic_ipi_send_single);
816c19f8971SMarc Zyngier 	if (WARN_ON(base_ipi <= 0))
81776cde263SHector Martin 		return -ENODEV;
81876cde263SHector Martin 
81976cde263SHector Martin 	set_smp_ipi_range(base_ipi, AIC_NR_SWIPI);
82076cde263SHector Martin 
82176cde263SHector Martin 	return 0;
82276cde263SHector Martin }
82376cde263SHector Martin 
aic_init_cpu(unsigned int cpu)82476cde263SHector Martin static int aic_init_cpu(unsigned int cpu)
82576cde263SHector Martin {
82676cde263SHector Martin 	/* Mask all hard-wired per-CPU IRQ/FIQ sources */
82776cde263SHector Martin 
82876cde263SHector Martin 	/* Pending Fast IPI FIQs */
829*59fc20baSKonrad Dybcio 	if (static_branch_likely(&use_fast_ipi))
83076cde263SHector Martin 		write_sysreg_s(IPI_SR_PENDING, SYS_IMP_APL_IPI_SR_EL1);
83176cde263SHector Martin 
83276cde263SHector Martin 	/* Timer FIQs */
83376cde263SHector Martin 	sysreg_clear_set(cntp_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK);
83476cde263SHector Martin 	sysreg_clear_set(cntv_ctl_el0, 0, ARCH_TIMER_CTRL_IT_MASK);
83576cde263SHector Martin 
83676cde263SHector Martin 	/* EL2-only (VHE mode) IRQ sources */
83776cde263SHector Martin 	if (is_kernel_in_hyp_mode()) {
83876cde263SHector Martin 		/* Guest timers */
83976cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2,
84076cde263SHector Martin 				   VM_TMR_FIQ_ENABLE_V | VM_TMR_FIQ_ENABLE_P, 0);
84176cde263SHector Martin 
84276cde263SHector Martin 		/* vGIC maintenance IRQ */
84376cde263SHector Martin 		sysreg_clear_set_s(SYS_ICH_HCR_EL2, ICH_HCR_EN, 0);
84476cde263SHector Martin 	}
84576cde263SHector Martin 
84676cde263SHector Martin 	/* PMC FIQ */
84776cde263SHector Martin 	sysreg_clear_set_s(SYS_IMP_APL_PMCR0_EL1, PMCR0_IMODE | PMCR0_IACT,
84876cde263SHector Martin 			   FIELD_PREP(PMCR0_IMODE, PMCR0_IMODE_OFF));
84976cde263SHector Martin 
85076cde263SHector Martin 	/* Uncore PMC FIQ */
851*59fc20baSKonrad Dybcio 	if (static_branch_likely(&use_fast_ipi)) {
85276cde263SHector Martin 		sysreg_clear_set_s(SYS_IMP_APL_UPMCR0_EL1, UPMCR0_IMODE,
85376cde263SHector Martin 				   FIELD_PREP(UPMCR0_IMODE, UPMCR0_IMODE_OFF));
854*59fc20baSKonrad Dybcio 	}
85576cde263SHector Martin 
85676cde263SHector Martin 	/* Commit all of the above */
85776cde263SHector Martin 	isb();
85876cde263SHector Martin 
859768d4435SHector Martin 	if (aic_irqc->info.version == 1) {
86076cde263SHector Martin 		/*
86176cde263SHector Martin 		 * Make sure the kernel's idea of logical CPU order is the same as AIC's
86276cde263SHector Martin 		 * If we ever end up with a mismatch here, we will have to introduce
86376cde263SHector Martin 		 * a mapping table similar to what other irqchip drivers do.
86476cde263SHector Martin 		 */
86576cde263SHector Martin 		WARN_ON(aic_ic_read(aic_irqc, AIC_WHOAMI) != smp_processor_id());
86676cde263SHector Martin 
86776cde263SHector Martin 		/*
86876cde263SHector Martin 		 * Always keep IPIs unmasked at the hardware level (except auto-masking
86976cde263SHector Martin 		 * by AIC during processing). We manage masks at the vIPI level.
8702cf68211SHector Martin 		 * These registers only exist on AICv1, AICv2 always uses fast IPIs.
87176cde263SHector Martin 		 */
87276cde263SHector Martin 		aic_ic_write(aic_irqc, AIC_IPI_ACK, AIC_IPI_SELF | AIC_IPI_OTHER);
8732cf68211SHector Martin 		if (static_branch_likely(&use_fast_ipi)) {
8742cf68211SHector Martin 			aic_ic_write(aic_irqc, AIC_IPI_MASK_SET, AIC_IPI_SELF | AIC_IPI_OTHER);
8752cf68211SHector Martin 		} else {
87676cde263SHector Martin 			aic_ic_write(aic_irqc, AIC_IPI_MASK_SET, AIC_IPI_SELF);
87776cde263SHector Martin 			aic_ic_write(aic_irqc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
8782cf68211SHector Martin 		}
879768d4435SHector Martin 	}
88076cde263SHector Martin 
88176cde263SHector Martin 	/* Initialize the local mask state */
88276cde263SHector Martin 	__this_cpu_write(aic_fiq_unmasked, 0);
88376cde263SHector Martin 
88476cde263SHector Martin 	return 0;
88576cde263SHector Martin }
88676cde263SHector Martin 
887b6ca556cSMarc Zyngier static struct gic_kvm_info vgic_info __initdata = {
888b6ca556cSMarc Zyngier 	.type			= GIC_V3,
889b6ca556cSMarc Zyngier 	.no_maint_irq_mask	= true,
890b6ca556cSMarc Zyngier 	.no_hw_deactivation	= true,
891b6ca556cSMarc Zyngier };
892b6ca556cSMarc Zyngier 
build_fiq_affinity(struct aic_irq_chip * ic,struct device_node * aff)893a5e88012SMarc Zyngier static void build_fiq_affinity(struct aic_irq_chip *ic, struct device_node *aff)
894a5e88012SMarc Zyngier {
895a5e88012SMarc Zyngier 	int i, n;
896a5e88012SMarc Zyngier 	u32 fiq;
897a5e88012SMarc Zyngier 
898a5e88012SMarc Zyngier 	if (of_property_read_u32(aff, "apple,fiq-index", &fiq) ||
899a5e88012SMarc Zyngier 	    WARN_ON(fiq >= AIC_NR_FIQ) || ic->fiq_aff[fiq])
900a5e88012SMarc Zyngier 		return;
901a5e88012SMarc Zyngier 
902a5e88012SMarc Zyngier 	n = of_property_count_elems_of_size(aff, "cpus", sizeof(u32));
903a5e88012SMarc Zyngier 	if (WARN_ON(n < 0))
904a5e88012SMarc Zyngier 		return;
905a5e88012SMarc Zyngier 
906dc29812dSMarc Zyngier 	ic->fiq_aff[fiq] = kzalloc(sizeof(*ic->fiq_aff[fiq]), GFP_KERNEL);
907a5e88012SMarc Zyngier 	if (!ic->fiq_aff[fiq])
908a5e88012SMarc Zyngier 		return;
909a5e88012SMarc Zyngier 
910a5e88012SMarc Zyngier 	for (i = 0; i < n; i++) {
911a5e88012SMarc Zyngier 		struct device_node *cpu_node;
912a5e88012SMarc Zyngier 		u32 cpu_phandle;
913a5e88012SMarc Zyngier 		int cpu;
914a5e88012SMarc Zyngier 
915a5e88012SMarc Zyngier 		if (of_property_read_u32_index(aff, "cpus", i, &cpu_phandle))
916a5e88012SMarc Zyngier 			continue;
917a5e88012SMarc Zyngier 
918a5e88012SMarc Zyngier 		cpu_node = of_find_node_by_phandle(cpu_phandle);
919a5e88012SMarc Zyngier 		if (WARN_ON(!cpu_node))
920a5e88012SMarc Zyngier 			continue;
921a5e88012SMarc Zyngier 
922a5e88012SMarc Zyngier 		cpu = of_cpu_node_to_id(cpu_node);
923b1ac803fSMiaoqian Lin 		of_node_put(cpu_node);
924a5e88012SMarc Zyngier 		if (WARN_ON(cpu < 0))
925a5e88012SMarc Zyngier 			continue;
926a5e88012SMarc Zyngier 
927a5e88012SMarc Zyngier 		cpumask_set_cpu(cpu, &ic->fiq_aff[fiq]->aff);
928a5e88012SMarc Zyngier 	}
929a5e88012SMarc Zyngier }
930a5e88012SMarc Zyngier 
aic_of_ic_init(struct device_node * node,struct device_node * parent)93176cde263SHector Martin static int __init aic_of_ic_init(struct device_node *node, struct device_node *parent)
93276cde263SHector Martin {
933a801f0eeSHector Martin 	int i, die;
934a801f0eeSHector Martin 	u32 off, start_off;
93576cde263SHector Martin 	void __iomem *regs;
93676cde263SHector Martin 	struct aic_irq_chip *irqc;
937a5e88012SMarc Zyngier 	struct device_node *affs;
9382cf68211SHector Martin 	const struct of_device_id *match;
93976cde263SHector Martin 
94076cde263SHector Martin 	regs = of_iomap(node, 0);
94176cde263SHector Martin 	if (WARN_ON(!regs))
94276cde263SHector Martin 		return -EIO;
94376cde263SHector Martin 
94476cde263SHector Martin 	irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
945768d4435SHector Martin 	if (!irqc) {
946768d4435SHector Martin 		iounmap(regs);
94776cde263SHector Martin 		return -ENOMEM;
948768d4435SHector Martin 	}
94976cde263SHector Martin 
95076cde263SHector Martin 	irqc->base = regs;
95176cde263SHector Martin 
9522cf68211SHector Martin 	match = of_match_node(aic_info_match, node);
9532cf68211SHector Martin 	if (!match)
954768d4435SHector Martin 		goto err_unmap;
95576cde263SHector Martin 
9562cf68211SHector Martin 	irqc->info = *(struct aic_info *)match->data;
9572cf68211SHector Martin 
9582cf68211SHector Martin 	aic_irqc = irqc;
9592cf68211SHector Martin 
960dc97fd6fSHector Martin 	switch (irqc->info.version) {
961dc97fd6fSHector Martin 	case 1: {
962dc97fd6fSHector Martin 		u32 info;
963dc97fd6fSHector Martin 
96476cde263SHector Martin 		info = aic_ic_read(irqc, AIC_INFO);
9657c841f5fSHector Martin 		irqc->nr_irq = FIELD_GET(AIC_INFO_NR_IRQ, info);
966dc97fd6fSHector Martin 		irqc->max_irq = AIC_MAX_IRQ;
967a801f0eeSHector Martin 		irqc->nr_die = irqc->max_die = 1;
968dc97fd6fSHector Martin 
969a801f0eeSHector Martin 		off = start_off = irqc->info.target_cpu;
970dc97fd6fSHector Martin 		off += sizeof(u32) * irqc->max_irq; /* TARGET_CPU */
971dc97fd6fSHector Martin 
972768d4435SHector Martin 		irqc->event = irqc->base;
973768d4435SHector Martin 
974768d4435SHector Martin 		break;
97576cde263SHector Martin 	}
976768d4435SHector Martin 	case 2: {
977768d4435SHector Martin 		u32 info1, info3;
978768d4435SHector Martin 
979768d4435SHector Martin 		info1 = aic_ic_read(irqc, AIC2_INFO1);
980768d4435SHector Martin 		info3 = aic_ic_read(irqc, AIC2_INFO3);
981768d4435SHector Martin 
982768d4435SHector Martin 		irqc->nr_irq = FIELD_GET(AIC2_INFO1_NR_IRQ, info1);
983768d4435SHector Martin 		irqc->max_irq = FIELD_GET(AIC2_INFO3_MAX_IRQ, info3);
984768d4435SHector Martin 		irqc->nr_die = FIELD_GET(AIC2_INFO1_LAST_DIE, info1) + 1;
985768d4435SHector Martin 		irqc->max_die = FIELD_GET(AIC2_INFO3_MAX_DIE, info3);
986768d4435SHector Martin 
987768d4435SHector Martin 		off = start_off = irqc->info.irq_cfg;
988768d4435SHector Martin 		off += sizeof(u32) * irqc->max_irq; /* IRQ_CFG */
989768d4435SHector Martin 
990768d4435SHector Martin 		irqc->event = of_iomap(node, 1);
991768d4435SHector Martin 		if (WARN_ON(!irqc->event))
992768d4435SHector Martin 			goto err_unmap;
993768d4435SHector Martin 
994dc97fd6fSHector Martin 		break;
995dc97fd6fSHector Martin 	}
996dc97fd6fSHector Martin 	}
997dc97fd6fSHector Martin 
998dc97fd6fSHector Martin 	irqc->info.sw_set = off;
999dc97fd6fSHector Martin 	off += sizeof(u32) * (irqc->max_irq >> 5); /* SW_SET */
1000dc97fd6fSHector Martin 	irqc->info.sw_clr = off;
1001dc97fd6fSHector Martin 	off += sizeof(u32) * (irqc->max_irq >> 5); /* SW_CLR */
1002dc97fd6fSHector Martin 	irqc->info.mask_set = off;
1003dc97fd6fSHector Martin 	off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_SET */
1004dc97fd6fSHector Martin 	irqc->info.mask_clr = off;
1005dc97fd6fSHector Martin 	off += sizeof(u32) * (irqc->max_irq >> 5); /* MASK_CLR */
1006dc97fd6fSHector Martin 	off += sizeof(u32) * (irqc->max_irq >> 5); /* HW_STATE */
100776cde263SHector Martin 
10085527b06cSNick Chan 	if (!irqc->info.fast_ipi)
10092cf68211SHector Martin 		static_branch_disable(&use_fast_ipi);
10102cf68211SHector Martin 
1011a845342eSNick Chan 	if (!irqc->info.local_fast_ipi)
1012a845342eSNick Chan 		static_branch_disable(&use_local_fast_ipi);
1013a845342eSNick Chan 
1014a801f0eeSHector Martin 	irqc->info.die_stride = off - start_off;
1015a801f0eeSHector Martin 
10167c841f5fSHector Martin 	irqc->hw_domain = irq_domain_create_tree(of_node_to_fwnode(node),
101776cde263SHector Martin 						 &aic_irq_domain_ops, irqc);
1018768d4435SHector Martin 	if (WARN_ON(!irqc->hw_domain))
1019768d4435SHector Martin 		goto err_unmap;
102076cde263SHector Martin 
102176cde263SHector Martin 	irq_domain_update_bus_token(irqc->hw_domain, DOMAIN_BUS_WIRED);
102276cde263SHector Martin 
1023768d4435SHector Martin 	if (aic_init_smp(irqc, node))
1024768d4435SHector Martin 		goto err_remove_domain;
102576cde263SHector Martin 
1026a5e88012SMarc Zyngier 	affs = of_get_child_by_name(node, "affinities");
1027a5e88012SMarc Zyngier 	if (affs) {
1028a5e88012SMarc Zyngier 		struct device_node *chld;
1029a5e88012SMarc Zyngier 
1030a5e88012SMarc Zyngier 		for_each_child_of_node(affs, chld)
1031a5e88012SMarc Zyngier 			build_fiq_affinity(irqc, chld);
1032a5e88012SMarc Zyngier 	}
10333d45670fSMiaoqian Lin 	of_node_put(affs);
1034a5e88012SMarc Zyngier 
103576cde263SHector Martin 	set_handle_irq(aic_handle_irq);
103676cde263SHector Martin 	set_handle_fiq(aic_handle_fiq);
103776cde263SHector Martin 
1038a801f0eeSHector Martin 	off = 0;
1039a801f0eeSHector Martin 	for (die = 0; die < irqc->nr_die; die++) {
10407c841f5fSHector Martin 		for (i = 0; i < BITS_TO_U32(irqc->nr_irq); i++)
1041a801f0eeSHector Martin 			aic_ic_write(irqc, irqc->info.mask_set + off + i * 4, U32_MAX);
10427c841f5fSHector Martin 		for (i = 0; i < BITS_TO_U32(irqc->nr_irq); i++)
1043a801f0eeSHector Martin 			aic_ic_write(irqc, irqc->info.sw_clr + off + i * 4, U32_MAX);
1044a801f0eeSHector Martin 		if (irqc->info.target_cpu)
10457c841f5fSHector Martin 			for (i = 0; i < irqc->nr_irq; i++)
1046a801f0eeSHector Martin 				aic_ic_write(irqc, irqc->info.target_cpu + off + i * 4, 1);
1047a801f0eeSHector Martin 		off += irqc->info.die_stride;
1048a801f0eeSHector Martin 	}
104976cde263SHector Martin 
1050768d4435SHector Martin 	if (irqc->info.version == 2) {
1051768d4435SHector Martin 		u32 config = aic_ic_read(irqc, AIC2_CONFIG);
1052768d4435SHector Martin 
1053768d4435SHector Martin 		config |= AIC2_CONFIG_ENABLE;
1054768d4435SHector Martin 		aic_ic_write(irqc, AIC2_CONFIG, config);
1055768d4435SHector Martin 	}
105676cde263SHector Martin 
105776cde263SHector Martin 	if (!is_kernel_in_hyp_mode())
105876cde263SHector Martin 		pr_info("Kernel running in EL1, mapping interrupts");
105976cde263SHector Martin 
10602cf68211SHector Martin 	if (static_branch_likely(&use_fast_ipi))
10612cf68211SHector Martin 		pr_info("Using Fast IPIs");
10622cf68211SHector Martin 
106376cde263SHector Martin 	cpuhp_setup_state(CPUHP_AP_IRQ_APPLE_AIC_STARTING,
106476cde263SHector Martin 			  "irqchip/apple-aic/ipi:starting",
106576cde263SHector Martin 			  aic_init_cpu, NULL);
106676cde263SHector Martin 
106713aad0c0SMarc Zyngier 	if (is_kernel_in_hyp_mode()) {
106813aad0c0SMarc Zyngier 		struct irq_fwspec mi = {
106913aad0c0SMarc Zyngier 			.fwnode		= of_node_to_fwnode(node),
107013aad0c0SMarc Zyngier 			.param_count	= 3,
107113aad0c0SMarc Zyngier 			.param		= {
107213aad0c0SMarc Zyngier 				[0]	= AIC_FIQ, /* This is a lie */
107313aad0c0SMarc Zyngier 				[1]	= AIC_VGIC_MI,
107413aad0c0SMarc Zyngier 				[2]	= IRQ_TYPE_LEVEL_HIGH,
107513aad0c0SMarc Zyngier 			},
107613aad0c0SMarc Zyngier 		};
107713aad0c0SMarc Zyngier 
1078ad818e60SMarc Zyngier 		vgic_info.maint_irq = irq_create_fwspec_mapping(&mi);
107913aad0c0SMarc Zyngier 		WARN_ON(!vgic_info.maint_irq);
108013aad0c0SMarc Zyngier 	}
108113aad0c0SMarc Zyngier 
1082b6ca556cSMarc Zyngier 	vgic_set_kvm_info(&vgic_info);
1083b6ca556cSMarc Zyngier 
1084a801f0eeSHector Martin 	pr_info("Initialized with %d/%d IRQs * %d/%d die(s), %d FIQs, %d vIPIs",
1085a801f0eeSHector Martin 		irqc->nr_irq, irqc->max_irq, irqc->nr_die, irqc->max_die, AIC_NR_FIQ, AIC_NR_SWIPI);
108676cde263SHector Martin 
108776cde263SHector Martin 	return 0;
1088768d4435SHector Martin 
1089768d4435SHector Martin err_remove_domain:
1090768d4435SHector Martin 	irq_domain_remove(irqc->hw_domain);
1091768d4435SHector Martin err_unmap:
1092768d4435SHector Martin 	if (irqc->event && irqc->event != irqc->base)
1093768d4435SHector Martin 		iounmap(irqc->event);
1094768d4435SHector Martin 	iounmap(irqc->base);
1095768d4435SHector Martin 	kfree(irqc);
1096768d4435SHector Martin 	return -ENODEV;
109776cde263SHector Martin }
109876cde263SHector Martin 
1099768d4435SHector Martin IRQCHIP_DECLARE(apple_aic, "apple,aic", aic_of_ic_init);
1100768d4435SHector Martin IRQCHIP_DECLARE(apple_aic2, "apple,aic2", aic_of_ic_init);
1101