new file mode 100644
@@ -0,0 +1,42 @@
+/*
+ * All ripped off from arch/arm/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_ARCH_GICV3_H_
+#define _ASMARM_ARCH_GICV3_H_
+
+#ifndef __ASSEMBLY__
+#include <libcflat.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define __stringify xstr
+
+#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2
+
+#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val));
+ isb();
+}
+
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+ u64 val = readl(addr);
+ val |= (u64)readl(addr + 4) << 32;
+ return val;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_ARCH_GICV3_H_ */
new file mode 100644
@@ -0,0 +1,92 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM_GIC_V3_H_
+#define _ASMARM_GIC_V3_H_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+#define GICD_CTLR 0x0000
+#define GICD_TYPER 0x0004
+#define GICD_IGROUPR 0x0080
+
+#define GICD_CTLR_RWP (1U << 31)
+#define GICD_CTLR_ARE_NS (1U << 4)
+#define GICD_CTLR_ENABLE_G1A (1U << 1)
+#define GICD_CTLR_ENABLE_G1 (1U << 0)
+
+#define GICR_TYPER 0x0008
+#define GICR_IGROUPR0 GICD_IGROUPR
+#define GICR_TYPER_LAST (1U << 4)
+
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/smp.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+struct gicv3_data {
+ void *dist_base;
+ void *redist_base[NR_CPUS];
+ unsigned int irq_nr;
+};
+extern struct gicv3_data gicv3_data;
+
+#define gicv3_dist_base() (gicv3_data.dist_base)
+#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()])
+#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K)
+
+extern int gicv3_init(void);
+extern void gicv3_enable_defaults(void);
+
+static inline void gicv3_do_wait_for_rwp(void *base)
+{
+ int count = 100000; /* 1s */
+
+ while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) {
+ if (!--count) {
+ printf("GICv3: RWP timeout!\n");
+ abort();
+ }
+ cpu_relax();
+ udelay(10);
+ };
+}
+
+static inline void gicv3_dist_wait_for_rwp(void)
+{
+ gicv3_do_wait_for_rwp(gicv3_dist_base());
+}
+
+static inline void gicv3_redist_wait_for_rwp(void)
+{
+ gicv3_do_wait_for_rwp(gicv3_redist_base());
+}
+
+static inline u32 mpidr_compress(u64 mpidr)
+{
+ u64 compressed = mpidr & MPIDR_HWID_BITMASK;
+
+ compressed = (((compressed >> 32) & 0xff) << 24) | compressed;
+ return compressed;
+}
+
+static inline u64 mpidr_uncompress(u32 compressed)
+{
+ u64 mpidr = ((u64)compressed >> 24) << 32;
+
+ mpidr |= compressed & MPIDR_HWID_BITMASK;
+ return mpidr;
+}
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V3_H_ */
@@ -7,6 +7,7 @@
#define _ASMARM_GIC_H_
#include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
#define GIC_CPU_CTRL 0x00
#define GIC_CPU_PRIMASK 0x04
@@ -8,9 +8,11 @@
#include <asm/io.h>
struct gicv2_data gicv2_data;
+struct gicv3_data gicv3_data;
/*
* Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
*/
static bool
gic_get_dt_bases(const char *compatible, void **base1, void **base2)
@@ -48,10 +50,18 @@ int gicv2_init(void)
&gicv2_data.dist_base, &gicv2_data.cpu_base);
}
+int gicv3_init(void)
+{
+ return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base,
+ &gicv3_data.redist_base[0]);
+}
+
int gic_init(void)
{
if (gicv2_init())
return 2;
+ else if (gicv3_init())
+ return 3;
return 0;
}
@@ -73,3 +83,49 @@ void gicv2_enable_defaults(void)
writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL);
}
+
+void gicv3_set_redist_base(void)
+{
+ u32 aff = mpidr_compress(get_mpidr());
+ void *ptr = gicv3_data.redist_base[0];
+ u64 typer;
+
+ do {
+ typer = gicv3_read_typer(ptr + GICR_TYPER);
+ if ((typer >> 32) == aff) {
+ gicv3_redist_base() = ptr;
+ return;
+ }
+ ptr += SZ_64K * 2; /* skip RD_base and SGI_base */
+ } while (!(typer & GICR_TYPER_LAST));
+ assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+ void *dist = gicv3_dist_base();
+ void *sgi_base;
+ unsigned int i;
+
+ gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+ if (gicv3_data.irq_nr > 1020)
+ gicv3_data.irq_nr = 1020;
+
+ writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+ dist + GICD_CTLR);
+ gicv3_dist_wait_for_rwp();
+
+ if (!gicv3_redist_base())
+ gicv3_set_redist_base();
+ sgi_base = gicv3_sgi_base();
+
+ writel(~0, sgi_base + GICR_IGROUPR0);
+ writel(GICD_INT_EN_SET_SGI, sgi_base + GIC_DIST_ENABLE_SET);
+
+ for (i = 0; i < 32; i += 4)
+ writel(GICD_INT_DEF_PRI_X4, sgi_base + GIC_DIST_PRI + i);
+ gicv3_redist_wait_for_rwp();
+
+ gicv3_write_pmr(0xf0);
+ gicv3_write_grpen1(1);
+}
new file mode 100644
@@ -0,0 +1,44 @@
+/*
+ * All ripped off from arch/arm64/include/asm/arch_gicv3.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_ARCH_GICV3_H_
+#define _ASMARM64_ARCH_GICV3_H_
+
+#include <asm/sysreg.h>
+
+#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+#define __stringify xstr
+
+/*
+ * Low-level accessors
+ *
+ * These system registers are 32 bits, but we make sure that the compiler
+ * sets the GP register's most significant bits to 0 with an explicit cast.
+ */
+
+static inline void gicv3_write_pmr(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+ asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+ isb();
+}
+
+#define gicv3_read_typer(c) readq(c)
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASMARM64_ARCH_GICV3_H_ */
new file mode 100644
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v3.h"
new file mode 100644
@@ -0,0 +1,44 @@
+/*
+ * Ripped off from arch/arm64/include/asm/sysreg.h
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#ifndef _ASMARM64_SYSREG_H_
+#define _ASMARM64_SYSREG_H_
+
+#define sys_reg(op0, op1, crn, crm, op2) \
+ ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5))
+
+#ifdef __ASSEMBLY__
+ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+ .equ .L__reg_num_x\num, \num
+ .endr
+ .equ .L__reg_num_xzr, 31
+
+ .macro mrs_s, rt, sreg
+ .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+
+ .macro msr_s, sreg, rt
+ .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt)
+ .endm
+#else
+asm(
+" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
+" .equ .L__reg_num_x\\num, \\num\n"
+" .endr\n"
+" .equ .L__reg_num_xzr, 31\n"
+"\n"
+" .macro mrs_s, rt, sreg\n"
+" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+"\n"
+" .macro msr_s, sreg, rt\n"
+" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n"
+" .endm\n"
+);
+#endif
+
+#endif /* _ASMARM64_SYSREG_H_ */
Signed-off-by: Andrew Jones <drjones@redhat.com> --- v4: - only take defines from kernel we need now [Andre] - simplify enable by not caring if we reinit the distributor [drew] v2: - configure irqs as NS GRP1 --- lib/arm/asm/arch_gicv3.h | 42 +++++++++++++++++++++ lib/arm/asm/gic-v3.h | 92 ++++++++++++++++++++++++++++++++++++++++++++++ lib/arm/asm/gic.h | 1 + lib/arm/gic.c | 56 ++++++++++++++++++++++++++++ lib/arm64/asm/arch_gicv3.h | 44 ++++++++++++++++++++++ lib/arm64/asm/gic-v3.h | 1 + lib/arm64/asm/sysreg.h | 44 ++++++++++++++++++++++ 7 files changed, 280 insertions(+) create mode 100644 lib/arm/asm/arch_gicv3.h create mode 100644 lib/arm/asm/gic-v3.h create mode 100644 lib/arm64/asm/arch_gicv3.h create mode 100644 lib/arm64/asm/gic-v3.h create mode 100644 lib/arm64/asm/sysreg.h -- 2.7.4