summaryrefslogtreecommitdiff
path: root/libcpu/aarch64/common/gic
diff options
context:
space:
mode:
authorBernard Xiong <[email protected]>2021-08-10 18:03:07 +0800
committerGitHub <[email protected]>2021-08-10 18:03:07 +0800
commita6df4391edc58dde02abc5bb20a64d5e2801ad9a (patch)
treed2ca4a46c582db9a1fcb8b4330abd8544fa35574 /libcpu/aarch64/common/gic
parent5e277b0325d569abdb459ad742e23b7b97854e1f (diff)
parentab47a8f5af188eaf2f2ed85c833b3c543678b8b6 (diff)
Merge pull request #4924 from GuEe-GUI/master
[bsp/virt64/aarch64]添加qemu-virt64-aarch64平台
Diffstat (limited to 'libcpu/aarch64/common/gic')
-rw-r--r--libcpu/aarch64/common/gic/SConscript6
-rw-r--r--libcpu/aarch64/common/gic/gic_pl390.c273
-rw-r--r--libcpu/aarch64/common/gic/gic_pl390.h27
3 files changed, 306 insertions, 0 deletions
diff --git a/libcpu/aarch64/common/gic/SConscript b/libcpu/aarch64/common/gic/SConscript
index b114ba7678..28daac87ff 100644
--- a/libcpu/aarch64/common/gic/SConscript
+++ b/libcpu/aarch64/common/gic/SConscript
@@ -5,6 +5,10 @@ from building import *
cwd = GetCurrentDir()
CPPPATH = [cwd]
+gic390_group = Split('''
+gic_pl390.c
+''')
+
gic400_group = Split('''
gic_pl400.c
''')
@@ -14,6 +18,8 @@ gic_pl500.c
''')
src = ()
+if GetDepend('BSP_USING_GIC390'):
+ src = gic390_group
if GetDepend('BSP_USING_GIC400'):
src = gic400_group
if GetDepend('BSP_USING_GIC500'):
diff --git a/libcpu/aarch64/common/gic/gic_pl390.c b/libcpu/aarch64/common/gic/gic_pl390.c
new file mode 100644
index 0000000000..a8e3b10d94
--- /dev/null
+++ b/libcpu/aarch64/common/gic/gic_pl390.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-31 GuEe-GUI the first version
+ */
+#include <rtthread.h>
+
+#include "gic_pl390.h"
+
+#define BIT(n) (1ul<<(n))
+#define MASK(n) (BIT(n)-1ul)
+
+#define IRQ_REG(IRQ) ((IRQ) / 32)
+#define IRQ_BIT(IRQ) BIT((IRQ) % 32)
+#define IRQ_MASK MASK(10)
+#define IRQ_SET_ALL 0xffffffff
+#define IS_IRQ_VALID(X) (((X)&IRQ_MASK) < GIC390_SPECIAL_IRQ_START)
+
+#define TARGET_CPU_ALLINT(CPU) \
+( \
+ (((CPU) & 0xff) << 0 ) | \
+ (((CPU) & 0xff) << 8 ) | \
+ (((CPU) & 0xff) << 16) | \
+ (((CPU) & 0xff) << 24) \
+)
+#define CPU(X) (1<<(X))
+#define TARGET_CPU0_ALLINT TARGET_CPU_ALLINT(CPU(0))
+
+/* memory map for GIC distributor */
+struct gic_dist_map
+{
+ rt_uint32_t enable; /* 0x000 */
+ rt_uint32_t ic_type; /* 0x004 */
+ rt_uint32_t dist_ident; /* 0x008 */
+ rt_uint32_t res1[29]; /* [0x00C, 0x080) */
+
+ rt_uint32_t security[32]; /* [0x080, 0x100) */
+
+ rt_uint32_t enable_set[32]; /* [0x100, 0x180) */
+ rt_uint32_t enable_clr[32]; /* [0x180, 0x200) */
+ rt_uint32_t pending_set[32]; /* [0x200, 0x280) */
+ rt_uint32_t pending_clr[32]; /* [0x280, 0x300) */
+ rt_uint32_t active[32]; /* [0x300, 0x380) */
+ rt_uint32_t res2[32]; /* [0x380, 0x400) */
+
+ rt_uint32_t priority[255]; /* [0x400, 0x7FC) */
+ rt_uint32_t res3; /* 0x7FC */
+
+ rt_uint32_t targets[255]; /* [0x800, 0xBFC) */
+ rt_uint32_t res4; /* 0xBFC */
+
+ rt_uint32_t config[64]; /* [0xC00, 0xD00) */
+
+ rt_uint32_t spi[32]; /* [0xD00, 0xD80) */
+ rt_uint32_t res5[20]; /* [0xD80, 0xDD0) */
+ rt_uint32_t res6; /* 0xDD0 */
+ rt_uint32_t legacy_int; /* 0xDD4 */
+ rt_uint32_t res7[2]; /* [0xDD8, 0xDE0) */
+ rt_uint32_t match_d; /* 0xDE0 */
+ rt_uint32_t enable_d; /* 0xDE4 */
+ rt_uint32_t res8[70]; /* [0xDE8, 0xF00) */
+
+ rt_uint32_t sgi_control; /* 0xF00 */
+ rt_uint32_t res9[3]; /* [0xF04, 0xF10) */
+ rt_uint32_t sgi_pending_clr[4]; /* [0xF10, 0xF20) */
+ rt_uint32_t res10[40]; /* [0xF20, 0xFC0) */
+
+ rt_uint32_t periph_id[12]; /* [0xFC0, 0xFF0) */
+ rt_uint32_t component_id[4]; /* [0xFF0, 0xFFF] */
+};
+
+/* memory map for GIC CPU interface */
+struct gic_cpu_iface_map
+{
+ rt_uint32_t icontrol; /* 0x000 */
+ rt_uint32_t pri_msk_c; /* 0x004 */
+ rt_uint32_t pb_c; /* 0x008 */
+ rt_uint32_t int_ack; /* 0x00C */
+ rt_uint32_t eoi; /* 0x010 */
+ rt_uint32_t run_priority; /* 0x014 */
+ rt_uint32_t hi_pend; /* 0x018 */
+ rt_uint32_t ns_alias_bp_c; /* 0x01C */
+ rt_uint32_t ns_alias_ack; /* 0x020 GIC400 only */
+ rt_uint32_t ns_alias_eoi; /* 0x024 GIC400 only */
+ rt_uint32_t ns_alias_hi_pend; /* 0x028 GIC400 only */
+
+ rt_uint32_t res1[5]; /* [0x02C, 0x040) */
+
+ rt_uint32_t integ_en_c; /* 0x040 PL390 only */
+ rt_uint32_t interrupt_out; /* 0x044 PL390 only */
+ rt_uint32_t res2[2]; /* [0x048, 0x050) */
+
+ rt_uint32_t match_c; /* 0x050 PL390 only */
+ rt_uint32_t enable_c; /* 0x054 PL390 only */
+
+ rt_uint32_t res3[30]; /* [0x058, 0x0FC) */
+ rt_uint32_t active_priority[4]; /* [0x0D0, 0xDC] GIC400 only */
+ rt_uint32_t ns_active_priority[4]; /* [0xE0,0xEC] GIC400 only */
+ rt_uint32_t res4[3];
+
+ rt_uint32_t cpu_if_ident; /* 0x0FC */
+ rt_uint32_t res5[948]; /* [0x100. 0xFC0) */
+
+ rt_uint32_t periph_id[8]; /* [0xFC0, 9xFF0) PL390 only */
+ rt_uint32_t component_id[4]; /* [0xFF0, 0xFFF] PL390 only */
+};
+
+volatile struct gic_dist_map *gic_dist =
+ (volatile struct gic_dist_map*)(GIC_PL390_DISTRIBUTOR_PPTR);
+
+volatile struct gic_cpu_iface_map *gic_cpuiface =
+ (volatile struct gic_cpu_iface_map*)(GIC_PL390_CONTROLLER_PPTR);
+
+/*
+ * The only sane way to get an GIC IRQ number that can be properly
+ * ACKED later is through the int_ack register. Unfortunately, reading
+ * this register changes the interrupt state to pending so future
+ * reads will not return the same value For this reason, we have a
+ * global variable to store the IRQ number.
+ */
+static rt_uint32_t active_irq = GIC390_IRQ_NONE;
+
+rt_inline int is_irq_edge_triggered(int irq)
+{
+ int word = irq / 16;
+ int bit = ((irq & 0xf) * 2);
+
+ return !!(gic_dist->config[word] & BIT(bit + 1));
+}
+
+rt_inline void dist_pending_clr(int irq)
+{
+ int word = irq / 32;
+ int bit = irq & 0x1f;
+ gic_dist->pending_clr[word] = BIT(bit);
+}
+
+rt_inline void dist_init(void)
+{
+ int i;
+ int nirqs = 32 * ((gic_dist->ic_type & 0x1f) + 1);
+ gic_dist->enable = 0;
+
+ for (i = 0; i < nirqs; i += 32)
+ {
+ /* disable */
+ gic_dist->enable_clr[i / 32] = IRQ_SET_ALL;
+ /* clear pending */
+ gic_dist->pending_clr[i / 32] = IRQ_SET_ALL;
+ }
+
+ /* reset interrupts priority */
+ for (i = 32; i < nirqs; i += 4)
+ {
+ gic_dist->priority[i / 4] = 0x0;
+ }
+
+ /*
+ * reset int target to cpu 0
+ * (Should really query which processor we're running on and use that)
+ */
+ for (i = 0; i < nirqs; i += 4)
+ {
+ gic_dist->targets[i / 4] = TARGET_CPU0_ALLINT;
+ }
+
+ /* level-triggered, 1-N */
+ for (i = 64; i < nirqs; i += 32)
+ {
+ gic_dist->config[i / 32] = 0;
+ }
+ /* enable the int controller */
+ gic_dist->enable = 1;
+}
+
+rt_inline void cpu_iface_init(void)
+{
+ rt_uint32_t i;
+
+ /* For non-Exynos4, the registers are banked per CPU, need to clear them */
+ gic_dist->enable_clr[0] = IRQ_SET_ALL;
+ gic_dist->pending_clr[0] = IRQ_SET_ALL;
+ gic_dist->priority[0] = 0x00;
+ /* put everything in group 0 */
+
+ /* clear any software generated interrupts */
+ for (i = 0; i < 16; i += 4)
+ {
+ gic_dist->sgi_pending_clr[i / 4] = IRQ_SET_ALL;
+ }
+
+ gic_cpuiface->icontrol = 0;
+ gic_cpuiface->pri_msk_c = 0x000000f0;
+ gic_cpuiface->pb_c = 0x00000003;
+
+ while (((i = gic_cpuiface->int_ack) & IRQ_MASK) != GIC390_IRQ_NONE)
+ {
+ gic_cpuiface->eoi = i;
+ }
+ gic_cpuiface->icontrol = 0x1;
+}
+
+
+void arm_gic_irq_init(void)
+{
+ dist_init();
+ cpu_iface_init();
+}
+
+int arm_gic_get_active_irq(void)
+{
+ int irq;
+ if (!IS_IRQ_VALID(active_irq))
+ {
+ active_irq = gic_cpuiface->int_ack;
+ }
+
+ if (IS_IRQ_VALID(active_irq))
+ {
+ irq = active_irq & IRQ_MASK;
+ }
+ else
+ {
+ irq = GIC390_IRQ_NONE;
+ }
+
+ return irq;
+}
+
+void arm_gic_mask(int irq)
+{
+ int word = irq / 32;
+ int bit = irq & 0x1f;
+
+ gic_dist->enable_clr[word] = BIT(bit);
+}
+
+void arm_gic_umask(int irq)
+{
+ int word = irq / 32;
+ int bit = irq & 0x1f;
+ gic_dist->enable_set[word] = BIT(bit);
+}
+
+void arm_gic_ack(int irq)
+{
+ if (!(IS_IRQ_VALID(active_irq) && (active_irq & IRQ_MASK) == irq))
+ {
+ return;
+ }
+ if (is_irq_edge_triggered(irq))
+ {
+ dist_pending_clr(irq);
+ }
+
+ gic_cpuiface->eoi = active_irq;
+ active_irq = GIC390_IRQ_NONE;
+}
+
+int rt_hw_interrupt_get_irq(void)
+{
+ return arm_gic_get_active_irq();
+}
+
+void rt_hw_interrupt_ack(int fiq_irq)
+{
+ return arm_gic_ack(fiq_irq);
+}
+
diff --git a/libcpu/aarch64/common/gic/gic_pl390.h b/libcpu/aarch64/common/gic/gic_pl390.h
new file mode 100644
index 0000000000..7ea574967d
--- /dev/null
+++ b/libcpu/aarch64/common/gic/gic_pl390.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2006-2021, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-07-31 GuEe-GUI the first version
+ */
+
+#ifndef GIC_PL390_H__
+#define GIC_PL390_H__
+
+#include <board.h>
+
+#define GIC390_SPECIAL_IRQ_START 1020
+#define GIC390_IRQ_NONE 1023
+
+void arm_gic_irq_init(void);
+
+int arm_gic_get_active_irq(void);
+void arm_gic_ack(int irq);
+
+void arm_gic_mask(int irq);
+void arm_gic_umask(int irq);
+
+#endif