xref: /openbmc/linux/tools/testing/selftests/kvm/lib/aarch64/gic_v3.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
128281652SRaghavendra Rao Ananta // SPDX-License-Identifier: GPL-2.0
228281652SRaghavendra Rao Ananta /*
328281652SRaghavendra Rao Ananta  * ARM Generic Interrupt Controller (GIC) v3 support
428281652SRaghavendra Rao Ananta  */
528281652SRaghavendra Rao Ananta 
628281652SRaghavendra Rao Ananta #include <linux/sizes.h>
728281652SRaghavendra Rao Ananta 
828281652SRaghavendra Rao Ananta #include "kvm_util.h"
928281652SRaghavendra Rao Ananta #include "processor.h"
1028281652SRaghavendra Rao Ananta #include "delay.h"
1128281652SRaghavendra Rao Ananta 
1228281652SRaghavendra Rao Ananta #include "gic_v3.h"
1328281652SRaghavendra Rao Ananta #include "gic_private.h"
1428281652SRaghavendra Rao Ananta 
1528281652SRaghavendra Rao Ananta struct gicv3_data {
1628281652SRaghavendra Rao Ananta 	void *dist_base;
1728281652SRaghavendra Rao Ananta 	void *redist_base[GICV3_MAX_CPUS];
1828281652SRaghavendra Rao Ananta 	unsigned int nr_cpus;
1928281652SRaghavendra Rao Ananta 	unsigned int nr_spis;
2028281652SRaghavendra Rao Ananta };
2128281652SRaghavendra Rao Ananta 
2228281652SRaghavendra Rao Ananta #define sgi_base_from_redist(redist_base)	(redist_base + SZ_64K)
2374506836SRicardo Koller #define DIST_BIT				(1U << 31)
2428281652SRaghavendra Rao Ananta 
2528281652SRaghavendra Rao Ananta enum gicv3_intid_range {
2628281652SRaghavendra Rao Ananta 	SGI_RANGE,
2728281652SRaghavendra Rao Ananta 	PPI_RANGE,
2828281652SRaghavendra Rao Ananta 	SPI_RANGE,
2928281652SRaghavendra Rao Ananta 	INVALID_RANGE,
3028281652SRaghavendra Rao Ananta };
3128281652SRaghavendra Rao Ananta 
3228281652SRaghavendra Rao Ananta static struct gicv3_data gicv3_data;
3328281652SRaghavendra Rao Ananta 
gicv3_gicd_wait_for_rwp(void)3428281652SRaghavendra Rao Ananta static void gicv3_gicd_wait_for_rwp(void)
3528281652SRaghavendra Rao Ananta {
3628281652SRaghavendra Rao Ananta 	unsigned int count = 100000; /* 1s */
3728281652SRaghavendra Rao Ananta 
3828281652SRaghavendra Rao Ananta 	while (readl(gicv3_data.dist_base + GICD_CTLR) & GICD_CTLR_RWP) {
3928281652SRaghavendra Rao Ananta 		GUEST_ASSERT(count--);
4028281652SRaghavendra Rao Ananta 		udelay(10);
4128281652SRaghavendra Rao Ananta 	}
4228281652SRaghavendra Rao Ananta }
4328281652SRaghavendra Rao Ananta 
gicv3_gicr_wait_for_rwp(void * redist_base)4428281652SRaghavendra Rao Ananta static void gicv3_gicr_wait_for_rwp(void *redist_base)
4528281652SRaghavendra Rao Ananta {
4628281652SRaghavendra Rao Ananta 	unsigned int count = 100000; /* 1s */
4728281652SRaghavendra Rao Ananta 
4828281652SRaghavendra Rao Ananta 	while (readl(redist_base + GICR_CTLR) & GICR_CTLR_RWP) {
4928281652SRaghavendra Rao Ananta 		GUEST_ASSERT(count--);
5028281652SRaghavendra Rao Ananta 		udelay(10);
5128281652SRaghavendra Rao Ananta 	}
5228281652SRaghavendra Rao Ananta }
5328281652SRaghavendra Rao Ananta 
gicv3_wait_for_rwp(uint32_t cpu_or_dist)5474506836SRicardo Koller static void gicv3_wait_for_rwp(uint32_t cpu_or_dist)
5574506836SRicardo Koller {
5674506836SRicardo Koller 	if (cpu_or_dist & DIST_BIT)
5774506836SRicardo Koller 		gicv3_gicd_wait_for_rwp();
5874506836SRicardo Koller 	else
5974506836SRicardo Koller 		gicv3_gicr_wait_for_rwp(gicv3_data.redist_base[cpu_or_dist]);
6074506836SRicardo Koller }
6174506836SRicardo Koller 
get_intid_range(unsigned int intid)6228281652SRaghavendra Rao Ananta static enum gicv3_intid_range get_intid_range(unsigned int intid)
6328281652SRaghavendra Rao Ananta {
6428281652SRaghavendra Rao Ananta 	switch (intid) {
6528281652SRaghavendra Rao Ananta 	case 0 ... 15:
6628281652SRaghavendra Rao Ananta 		return SGI_RANGE;
6728281652SRaghavendra Rao Ananta 	case 16 ... 31:
6828281652SRaghavendra Rao Ananta 		return PPI_RANGE;
6928281652SRaghavendra Rao Ananta 	case 32 ... 1019:
7028281652SRaghavendra Rao Ananta 		return SPI_RANGE;
7128281652SRaghavendra Rao Ananta 	}
7228281652SRaghavendra Rao Ananta 
7328281652SRaghavendra Rao Ananta 	/* We should not be reaching here */
7428281652SRaghavendra Rao Ananta 	GUEST_ASSERT(0);
7528281652SRaghavendra Rao Ananta 
7628281652SRaghavendra Rao Ananta 	return INVALID_RANGE;
7728281652SRaghavendra Rao Ananta }
7828281652SRaghavendra Rao Ananta 
gicv3_read_iar(void)7928281652SRaghavendra Rao Ananta static uint64_t gicv3_read_iar(void)
8028281652SRaghavendra Rao Ananta {
8128281652SRaghavendra Rao Ananta 	uint64_t irqstat = read_sysreg_s(SYS_ICC_IAR1_EL1);
8228281652SRaghavendra Rao Ananta 
8328281652SRaghavendra Rao Ananta 	dsb(sy);
8428281652SRaghavendra Rao Ananta 	return irqstat;
8528281652SRaghavendra Rao Ananta }
8628281652SRaghavendra Rao Ananta 
gicv3_write_eoir(uint32_t irq)8728281652SRaghavendra Rao Ananta static void gicv3_write_eoir(uint32_t irq)
8828281652SRaghavendra Rao Ananta {
8928281652SRaghavendra Rao Ananta 	write_sysreg_s(irq, SYS_ICC_EOIR1_EL1);
9028281652SRaghavendra Rao Ananta 	isb();
9128281652SRaghavendra Rao Ananta }
9228281652SRaghavendra Rao Ananta 
gicv3_write_dir(uint32_t irq)9317ce617bSRicardo Koller static void gicv3_write_dir(uint32_t irq)
9417ce617bSRicardo Koller {
9517ce617bSRicardo Koller 	write_sysreg_s(irq, SYS_ICC_DIR_EL1);
9617ce617bSRicardo Koller 	isb();
9717ce617bSRicardo Koller }
9817ce617bSRicardo Koller 
gicv3_set_priority_mask(uint64_t mask)9917ce617bSRicardo Koller static void gicv3_set_priority_mask(uint64_t mask)
10017ce617bSRicardo Koller {
10117ce617bSRicardo Koller 	write_sysreg_s(mask, SYS_ICC_PMR_EL1);
10217ce617bSRicardo Koller }
10317ce617bSRicardo Koller 
gicv3_set_eoi_split(bool split)10417ce617bSRicardo Koller static void gicv3_set_eoi_split(bool split)
10517ce617bSRicardo Koller {
10617ce617bSRicardo Koller 	uint32_t val;
10717ce617bSRicardo Koller 
108*a5cd38fdSRicardo Koller 	/*
109*a5cd38fdSRicardo Koller 	 * All other fields are read-only, so no need to read CTLR first. In
11017ce617bSRicardo Koller 	 * fact, the kernel does the same.
11117ce617bSRicardo Koller 	 */
11217ce617bSRicardo Koller 	val = split ? (1U << 1) : 0;
11317ce617bSRicardo Koller 	write_sysreg_s(val, SYS_ICC_CTLR_EL1);
11417ce617bSRicardo Koller 	isb();
11517ce617bSRicardo Koller }
11617ce617bSRicardo Koller 
gicv3_reg_readl(uint32_t cpu_or_dist,uint64_t offset)11774506836SRicardo Koller uint32_t gicv3_reg_readl(uint32_t cpu_or_dist, uint64_t offset)
11874506836SRicardo Koller {
11974506836SRicardo Koller 	void *base = cpu_or_dist & DIST_BIT ? gicv3_data.dist_base
12074506836SRicardo Koller 		: sgi_base_from_redist(gicv3_data.redist_base[cpu_or_dist]);
12174506836SRicardo Koller 	return readl(base + offset);
12274506836SRicardo Koller }
12374506836SRicardo Koller 
gicv3_reg_writel(uint32_t cpu_or_dist,uint64_t offset,uint32_t reg_val)12474506836SRicardo Koller void gicv3_reg_writel(uint32_t cpu_or_dist, uint64_t offset, uint32_t reg_val)
12574506836SRicardo Koller {
12674506836SRicardo Koller 	void *base = cpu_or_dist & DIST_BIT ? gicv3_data.dist_base
12774506836SRicardo Koller 		: sgi_base_from_redist(gicv3_data.redist_base[cpu_or_dist]);
12874506836SRicardo Koller 	writel(reg_val, base + offset);
12974506836SRicardo Koller }
13074506836SRicardo Koller 
gicv3_getl_fields(uint32_t cpu_or_dist,uint64_t offset,uint32_t mask)13174506836SRicardo Koller uint32_t gicv3_getl_fields(uint32_t cpu_or_dist, uint64_t offset, uint32_t mask)
13274506836SRicardo Koller {
13374506836SRicardo Koller 	return gicv3_reg_readl(cpu_or_dist, offset) & mask;
13474506836SRicardo Koller }
13574506836SRicardo Koller 
gicv3_setl_fields(uint32_t cpu_or_dist,uint64_t offset,uint32_t mask,uint32_t reg_val)13674506836SRicardo Koller void gicv3_setl_fields(uint32_t cpu_or_dist, uint64_t offset,
13774506836SRicardo Koller 		uint32_t mask, uint32_t reg_val)
13874506836SRicardo Koller {
13974506836SRicardo Koller 	uint32_t tmp = gicv3_reg_readl(cpu_or_dist, offset) & ~mask;
14074506836SRicardo Koller 
14174506836SRicardo Koller 	tmp |= (reg_val & mask);
14274506836SRicardo Koller 	gicv3_reg_writel(cpu_or_dist, offset, tmp);
14374506836SRicardo Koller }
14474506836SRicardo Koller 
14574506836SRicardo Koller /*
14674506836SRicardo Koller  * We use a single offset for the distributor and redistributor maps as they
14774506836SRicardo Koller  * have the same value in both. The only exceptions are registers that only
14874506836SRicardo Koller  * exist in one and not the other, like GICR_WAKER that doesn't exist in the
14974506836SRicardo Koller  * distributor map. Such registers are conveniently marked as reserved in the
15074506836SRicardo Koller  * map that doesn't implement it; like GICR_WAKER's offset of 0x0014 being
15174506836SRicardo Koller  * marked as "Reserved" in the Distributor map.
15274506836SRicardo Koller  */
gicv3_access_reg(uint32_t intid,uint64_t offset,uint32_t reg_bits,uint32_t bits_per_field,bool write,uint32_t * val)15374506836SRicardo Koller static void gicv3_access_reg(uint32_t intid, uint64_t offset,
15474506836SRicardo Koller 		uint32_t reg_bits, uint32_t bits_per_field,
15574506836SRicardo Koller 		bool write, uint32_t *val)
15628281652SRaghavendra Rao Ananta {
15728281652SRaghavendra Rao Ananta 	uint32_t cpu = guest_get_vcpuid();
15828281652SRaghavendra Rao Ananta 	enum gicv3_intid_range intid_range = get_intid_range(intid);
15974506836SRicardo Koller 	uint32_t fields_per_reg, index, mask, shift;
16074506836SRicardo Koller 	uint32_t cpu_or_dist;
16128281652SRaghavendra Rao Ananta 
16274506836SRicardo Koller 	GUEST_ASSERT(bits_per_field <= reg_bits);
163cc94d47cSRicardo Koller 	GUEST_ASSERT(!write || *val < (1U << bits_per_field));
164*a5cd38fdSRicardo Koller 	/*
165*a5cd38fdSRicardo Koller 	 * This function does not support 64 bit accesses. Just asserting here
166*a5cd38fdSRicardo Koller 	 * until we implement readq/writeq.
16774506836SRicardo Koller 	 */
16874506836SRicardo Koller 	GUEST_ASSERT(reg_bits == 32);
16928281652SRaghavendra Rao Ananta 
17074506836SRicardo Koller 	fields_per_reg = reg_bits / bits_per_field;
17174506836SRicardo Koller 	index = intid % fields_per_reg;
17274506836SRicardo Koller 	shift = index * bits_per_field;
17374506836SRicardo Koller 	mask = ((1U << bits_per_field) - 1) << shift;
17474506836SRicardo Koller 
17574506836SRicardo Koller 	/* Set offset to the actual register holding intid's config. */
17674506836SRicardo Koller 	offset += (intid / fields_per_reg) * (reg_bits / 8);
17774506836SRicardo Koller 
17874506836SRicardo Koller 	cpu_or_dist = (intid_range == SPI_RANGE) ? DIST_BIT : cpu;
17974506836SRicardo Koller 
18074506836SRicardo Koller 	if (write)
18174506836SRicardo Koller 		gicv3_setl_fields(cpu_or_dist, offset, mask, *val << shift);
18274506836SRicardo Koller 	*val = gicv3_getl_fields(cpu_or_dist, offset, mask) >> shift;
18328281652SRaghavendra Rao Ananta }
18474506836SRicardo Koller 
gicv3_write_reg(uint32_t intid,uint64_t offset,uint32_t reg_bits,uint32_t bits_per_field,uint32_t val)18574506836SRicardo Koller static void gicv3_write_reg(uint32_t intid, uint64_t offset,
18674506836SRicardo Koller 		uint32_t reg_bits, uint32_t bits_per_field, uint32_t val)
18774506836SRicardo Koller {
18874506836SRicardo Koller 	gicv3_access_reg(intid, offset, reg_bits,
18974506836SRicardo Koller 			bits_per_field, true, &val);
19074506836SRicardo Koller }
19174506836SRicardo Koller 
gicv3_read_reg(uint32_t intid,uint64_t offset,uint32_t reg_bits,uint32_t bits_per_field)19274506836SRicardo Koller static uint32_t gicv3_read_reg(uint32_t intid, uint64_t offset,
19374506836SRicardo Koller 		uint32_t reg_bits, uint32_t bits_per_field)
19474506836SRicardo Koller {
19574506836SRicardo Koller 	uint32_t val;
19674506836SRicardo Koller 
19774506836SRicardo Koller 	gicv3_access_reg(intid, offset, reg_bits,
19874506836SRicardo Koller 			bits_per_field, false, &val);
19974506836SRicardo Koller 	return val;
20028281652SRaghavendra Rao Ananta }
20128281652SRaghavendra Rao Ananta 
gicv3_set_priority(uint32_t intid,uint32_t prio)20217ce617bSRicardo Koller static void gicv3_set_priority(uint32_t intid, uint32_t prio)
20317ce617bSRicardo Koller {
20417ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_IPRIORITYR, 32, 8, prio);
20517ce617bSRicardo Koller }
20617ce617bSRicardo Koller 
20717ce617bSRicardo Koller /* Sets the intid to be level-sensitive or edge-triggered. */
gicv3_irq_set_config(uint32_t intid,bool is_edge)20817ce617bSRicardo Koller static void gicv3_irq_set_config(uint32_t intid, bool is_edge)
20917ce617bSRicardo Koller {
21017ce617bSRicardo Koller 	uint32_t val;
21117ce617bSRicardo Koller 
21217ce617bSRicardo Koller 	/* N/A for private interrupts. */
21317ce617bSRicardo Koller 	GUEST_ASSERT(get_intid_range(intid) == SPI_RANGE);
21417ce617bSRicardo Koller 	val = is_edge ? 2 : 0;
21517ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ICFGR, 32, 2, val);
21617ce617bSRicardo Koller }
21717ce617bSRicardo Koller 
gicv3_irq_enable(uint32_t intid)21817ce617bSRicardo Koller static void gicv3_irq_enable(uint32_t intid)
21928281652SRaghavendra Rao Ananta {
22074506836SRicardo Koller 	bool is_spi = get_intid_range(intid) == SPI_RANGE;
22174506836SRicardo Koller 	uint32_t cpu = guest_get_vcpuid();
22274506836SRicardo Koller 
22317ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ISENABLER, 32, 1, 1);
22474506836SRicardo Koller 	gicv3_wait_for_rwp(is_spi ? DIST_BIT : cpu);
22528281652SRaghavendra Rao Ananta }
22628281652SRaghavendra Rao Ananta 
gicv3_irq_disable(uint32_t intid)22717ce617bSRicardo Koller static void gicv3_irq_disable(uint32_t intid)
22828281652SRaghavendra Rao Ananta {
22974506836SRicardo Koller 	bool is_spi = get_intid_range(intid) == SPI_RANGE;
23074506836SRicardo Koller 	uint32_t cpu = guest_get_vcpuid();
23174506836SRicardo Koller 
23217ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ICENABLER, 32, 1, 1);
23374506836SRicardo Koller 	gicv3_wait_for_rwp(is_spi ? DIST_BIT : cpu);
23428281652SRaghavendra Rao Ananta }
23528281652SRaghavendra Rao Ananta 
gicv3_irq_set_active(uint32_t intid)23617ce617bSRicardo Koller static void gicv3_irq_set_active(uint32_t intid)
23717ce617bSRicardo Koller {
23817ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ISACTIVER, 32, 1, 1);
23917ce617bSRicardo Koller }
24017ce617bSRicardo Koller 
gicv3_irq_clear_active(uint32_t intid)24117ce617bSRicardo Koller static void gicv3_irq_clear_active(uint32_t intid)
24217ce617bSRicardo Koller {
24317ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ICACTIVER, 32, 1, 1);
24417ce617bSRicardo Koller }
24517ce617bSRicardo Koller 
gicv3_irq_get_active(uint32_t intid)24617ce617bSRicardo Koller static bool gicv3_irq_get_active(uint32_t intid)
24717ce617bSRicardo Koller {
24817ce617bSRicardo Koller 	return gicv3_read_reg(intid, GICD_ISACTIVER, 32, 1);
24917ce617bSRicardo Koller }
25017ce617bSRicardo Koller 
gicv3_irq_set_pending(uint32_t intid)25117ce617bSRicardo Koller static void gicv3_irq_set_pending(uint32_t intid)
25217ce617bSRicardo Koller {
25317ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ISPENDR, 32, 1, 1);
25417ce617bSRicardo Koller }
25517ce617bSRicardo Koller 
gicv3_irq_clear_pending(uint32_t intid)25617ce617bSRicardo Koller static void gicv3_irq_clear_pending(uint32_t intid)
25717ce617bSRicardo Koller {
25817ce617bSRicardo Koller 	gicv3_write_reg(intid, GICD_ICPENDR, 32, 1, 1);
25917ce617bSRicardo Koller }
26017ce617bSRicardo Koller 
gicv3_irq_get_pending(uint32_t intid)26117ce617bSRicardo Koller static bool gicv3_irq_get_pending(uint32_t intid)
26217ce617bSRicardo Koller {
26317ce617bSRicardo Koller 	return gicv3_read_reg(intid, GICD_ISPENDR, 32, 1);
26417ce617bSRicardo Koller }
26517ce617bSRicardo Koller 
gicv3_enable_redist(void * redist_base)26628281652SRaghavendra Rao Ananta static void gicv3_enable_redist(void *redist_base)
26728281652SRaghavendra Rao Ananta {
26828281652SRaghavendra Rao Ananta 	uint32_t val = readl(redist_base + GICR_WAKER);
26928281652SRaghavendra Rao Ananta 	unsigned int count = 100000; /* 1s */
27028281652SRaghavendra Rao Ananta 
27128281652SRaghavendra Rao Ananta 	val &= ~GICR_WAKER_ProcessorSleep;
27228281652SRaghavendra Rao Ananta 	writel(val, redist_base + GICR_WAKER);
27328281652SRaghavendra Rao Ananta 
27428281652SRaghavendra Rao Ananta 	/* Wait until the processor is 'active' */
27528281652SRaghavendra Rao Ananta 	while (readl(redist_base + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
27628281652SRaghavendra Rao Ananta 		GUEST_ASSERT(count--);
27728281652SRaghavendra Rao Ananta 		udelay(10);
27828281652SRaghavendra Rao Ananta 	}
27928281652SRaghavendra Rao Ananta }
28028281652SRaghavendra Rao Ananta 
gicr_base_cpu(void * redist_base,uint32_t cpu)28128281652SRaghavendra Rao Ananta static inline void *gicr_base_cpu(void *redist_base, uint32_t cpu)
28228281652SRaghavendra Rao Ananta {
28328281652SRaghavendra Rao Ananta 	/* Align all the redistributors sequentially */
28428281652SRaghavendra Rao Ananta 	return redist_base + cpu * SZ_64K * 2;
28528281652SRaghavendra Rao Ananta }
28628281652SRaghavendra Rao Ananta 
gicv3_cpu_init(unsigned int cpu,void * redist_base)28728281652SRaghavendra Rao Ananta static void gicv3_cpu_init(unsigned int cpu, void *redist_base)
28828281652SRaghavendra Rao Ananta {
28928281652SRaghavendra Rao Ananta 	void *sgi_base;
29028281652SRaghavendra Rao Ananta 	unsigned int i;
29128281652SRaghavendra Rao Ananta 	void *redist_base_cpu;
29228281652SRaghavendra Rao Ananta 
29328281652SRaghavendra Rao Ananta 	GUEST_ASSERT(cpu < gicv3_data.nr_cpus);
29428281652SRaghavendra Rao Ananta 
29528281652SRaghavendra Rao Ananta 	redist_base_cpu = gicr_base_cpu(redist_base, cpu);
29628281652SRaghavendra Rao Ananta 	sgi_base = sgi_base_from_redist(redist_base_cpu);
29728281652SRaghavendra Rao Ananta 
29828281652SRaghavendra Rao Ananta 	gicv3_enable_redist(redist_base_cpu);
29928281652SRaghavendra Rao Ananta 
30028281652SRaghavendra Rao Ananta 	/*
30128281652SRaghavendra Rao Ananta 	 * Mark all the SGI and PPI interrupts as non-secure Group-1.
30228281652SRaghavendra Rao Ananta 	 * Also, deactivate and disable them.
30328281652SRaghavendra Rao Ananta 	 */
30428281652SRaghavendra Rao Ananta 	writel(~0, sgi_base + GICR_IGROUPR0);
30528281652SRaghavendra Rao Ananta 	writel(~0, sgi_base + GICR_ICACTIVER0);
30628281652SRaghavendra Rao Ananta 	writel(~0, sgi_base + GICR_ICENABLER0);
30728281652SRaghavendra Rao Ananta 
30828281652SRaghavendra Rao Ananta 	/* Set a default priority for all the SGIs and PPIs */
30928281652SRaghavendra Rao Ananta 	for (i = 0; i < 32; i += 4)
31028281652SRaghavendra Rao Ananta 		writel(GICD_INT_DEF_PRI_X4,
31128281652SRaghavendra Rao Ananta 				sgi_base + GICR_IPRIORITYR0 + i);
31228281652SRaghavendra Rao Ananta 
31328281652SRaghavendra Rao Ananta 	gicv3_gicr_wait_for_rwp(redist_base_cpu);
31428281652SRaghavendra Rao Ananta 
31528281652SRaghavendra Rao Ananta 	/* Enable the GIC system register (ICC_*) access */
31628281652SRaghavendra Rao Ananta 	write_sysreg_s(read_sysreg_s(SYS_ICC_SRE_EL1) | ICC_SRE_EL1_SRE,
31728281652SRaghavendra Rao Ananta 			SYS_ICC_SRE_EL1);
31828281652SRaghavendra Rao Ananta 
31928281652SRaghavendra Rao Ananta 	/* Set a default priority threshold */
32028281652SRaghavendra Rao Ananta 	write_sysreg_s(ICC_PMR_DEF_PRIO, SYS_ICC_PMR_EL1);
32128281652SRaghavendra Rao Ananta 
32228281652SRaghavendra Rao Ananta 	/* Enable non-secure Group-1 interrupts */
32328281652SRaghavendra Rao Ananta 	write_sysreg_s(ICC_IGRPEN1_EL1_ENABLE, SYS_ICC_GRPEN1_EL1);
32428281652SRaghavendra Rao Ananta 
32528281652SRaghavendra Rao Ananta 	gicv3_data.redist_base[cpu] = redist_base_cpu;
32628281652SRaghavendra Rao Ananta }
32728281652SRaghavendra Rao Ananta 
gicv3_dist_init(void)32828281652SRaghavendra Rao Ananta static void gicv3_dist_init(void)
32928281652SRaghavendra Rao Ananta {
33028281652SRaghavendra Rao Ananta 	void *dist_base = gicv3_data.dist_base;
33128281652SRaghavendra Rao Ananta 	unsigned int i;
33228281652SRaghavendra Rao Ananta 
33328281652SRaghavendra Rao Ananta 	/* Disable the distributor until we set things up */
33428281652SRaghavendra Rao Ananta 	writel(0, dist_base + GICD_CTLR);
33528281652SRaghavendra Rao Ananta 	gicv3_gicd_wait_for_rwp();
33628281652SRaghavendra Rao Ananta 
33728281652SRaghavendra Rao Ananta 	/*
33828281652SRaghavendra Rao Ananta 	 * Mark all the SPI interrupts as non-secure Group-1.
33928281652SRaghavendra Rao Ananta 	 * Also, deactivate and disable them.
34028281652SRaghavendra Rao Ananta 	 */
34128281652SRaghavendra Rao Ananta 	for (i = 32; i < gicv3_data.nr_spis; i += 32) {
34228281652SRaghavendra Rao Ananta 		writel(~0, dist_base + GICD_IGROUPR + i / 8);
34328281652SRaghavendra Rao Ananta 		writel(~0, dist_base + GICD_ICACTIVER + i / 8);
34428281652SRaghavendra Rao Ananta 		writel(~0, dist_base + GICD_ICENABLER + i / 8);
34528281652SRaghavendra Rao Ananta 	}
34628281652SRaghavendra Rao Ananta 
34728281652SRaghavendra Rao Ananta 	/* Set a default priority for all the SPIs */
34828281652SRaghavendra Rao Ananta 	for (i = 32; i < gicv3_data.nr_spis; i += 4)
34928281652SRaghavendra Rao Ananta 		writel(GICD_INT_DEF_PRI_X4,
35028281652SRaghavendra Rao Ananta 				dist_base + GICD_IPRIORITYR + i);
35128281652SRaghavendra Rao Ananta 
35228281652SRaghavendra Rao Ananta 	/* Wait for the settings to sync-in */
35328281652SRaghavendra Rao Ananta 	gicv3_gicd_wait_for_rwp();
35428281652SRaghavendra Rao Ananta 
35528281652SRaghavendra Rao Ananta 	/* Finally, enable the distributor globally with ARE */
35628281652SRaghavendra Rao Ananta 	writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A |
35728281652SRaghavendra Rao Ananta 			GICD_CTLR_ENABLE_G1, dist_base + GICD_CTLR);
35828281652SRaghavendra Rao Ananta 	gicv3_gicd_wait_for_rwp();
35928281652SRaghavendra Rao Ananta }
36028281652SRaghavendra Rao Ananta 
gicv3_init(unsigned int nr_cpus,void * dist_base)36128281652SRaghavendra Rao Ananta static void gicv3_init(unsigned int nr_cpus, void *dist_base)
36228281652SRaghavendra Rao Ananta {
36328281652SRaghavendra Rao Ananta 	GUEST_ASSERT(nr_cpus <= GICV3_MAX_CPUS);
36428281652SRaghavendra Rao Ananta 
36528281652SRaghavendra Rao Ananta 	gicv3_data.nr_cpus = nr_cpus;
36628281652SRaghavendra Rao Ananta 	gicv3_data.dist_base = dist_base;
36728281652SRaghavendra Rao Ananta 	gicv3_data.nr_spis = GICD_TYPER_SPIS(
36828281652SRaghavendra Rao Ananta 				readl(gicv3_data.dist_base + GICD_TYPER));
36928281652SRaghavendra Rao Ananta 	if (gicv3_data.nr_spis > 1020)
37028281652SRaghavendra Rao Ananta 		gicv3_data.nr_spis = 1020;
37128281652SRaghavendra Rao Ananta 
37228281652SRaghavendra Rao Ananta 	/*
37328281652SRaghavendra Rao Ananta 	 * Initialize only the distributor for now.
37428281652SRaghavendra Rao Ananta 	 * The redistributor and CPU interfaces are initialized
37528281652SRaghavendra Rao Ananta 	 * later for every PE.
37628281652SRaghavendra Rao Ananta 	 */
37728281652SRaghavendra Rao Ananta 	gicv3_dist_init();
37828281652SRaghavendra Rao Ananta }
37928281652SRaghavendra Rao Ananta 
38028281652SRaghavendra Rao Ananta const struct gic_common_ops gicv3_ops = {
38128281652SRaghavendra Rao Ananta 	.gic_init = gicv3_init,
38228281652SRaghavendra Rao Ananta 	.gic_cpu_init = gicv3_cpu_init,
38328281652SRaghavendra Rao Ananta 	.gic_irq_enable = gicv3_irq_enable,
38428281652SRaghavendra Rao Ananta 	.gic_irq_disable = gicv3_irq_disable,
38528281652SRaghavendra Rao Ananta 	.gic_read_iar = gicv3_read_iar,
38628281652SRaghavendra Rao Ananta 	.gic_write_eoir = gicv3_write_eoir,
38717ce617bSRicardo Koller 	.gic_write_dir = gicv3_write_dir,
38817ce617bSRicardo Koller 	.gic_set_priority_mask = gicv3_set_priority_mask,
38917ce617bSRicardo Koller 	.gic_set_eoi_split = gicv3_set_eoi_split,
39017ce617bSRicardo Koller 	.gic_set_priority = gicv3_set_priority,
39117ce617bSRicardo Koller 	.gic_irq_set_active = gicv3_irq_set_active,
39217ce617bSRicardo Koller 	.gic_irq_clear_active = gicv3_irq_clear_active,
39317ce617bSRicardo Koller 	.gic_irq_get_active = gicv3_irq_get_active,
39417ce617bSRicardo Koller 	.gic_irq_set_pending = gicv3_irq_set_pending,
39517ce617bSRicardo Koller 	.gic_irq_clear_pending = gicv3_irq_clear_pending,
39617ce617bSRicardo Koller 	.gic_irq_get_pending = gicv3_irq_get_pending,
39717ce617bSRicardo Koller 	.gic_irq_set_config = gicv3_irq_set_config,
39828281652SRaghavendra Rao Ananta };
399