1 /*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <config.h>
8 #include <arch/machine/gic_v2.h>
9
10 #define TARGET_CPU_ALLINT(CPU) ( \
11 ( ((CPU)&0xff)<<0u ) |\
12 ( ((CPU)&0xff)<<8u ) |\
13 ( ((CPU)&0xff)<<16u ) |\
14 ( ((CPU)&0xff)<<24u ) \
15 )
16 #define TARGET_CPU0_ALLINT TARGET_CPU_ALLINT(BIT(0))
17
18 /* Use this to forward interrupts to all CPUs when debugging */
19 #define TARGET_CPU_ALL_ALLINT TARGET_CPU_ALLINT(0xff)
20
21 #define IRQ_SET_ALL 0xffffffff;
22
23 #ifndef GIC_V2_DISTRIBUTOR_PPTR
24 #error GIC_V2_DISTRIBUTOR_PPTR must be defined for virtual memory access to the gic distributer
25 #else /* GIC_DISTRIBUTOR_PPTR */
26 volatile struct gic_dist_map *const gic_dist =
27 (volatile struct gic_dist_map *)(GIC_V2_DISTRIBUTOR_PPTR);
28 #endif /* GIC_DISTRIBUTOR_PPTR */
29
30 #ifndef GIC_V2_CONTROLLER_PPTR
31 #error GIC_V2_CONTROLLER_PPTR must be defined for virtual memory access to the gic cpu interface
32 #else /* GIC_CONTROLLER_PPTR */
33 volatile struct gic_cpu_iface_map *const gic_cpuiface =
34 (volatile struct gic_cpu_iface_map *)(GIC_V2_CONTROLLER_PPTR);
35 #endif /* GIC_CONTROLLER_PPTR */
36
37 word_t active_irq[CONFIG_MAX_NUM_NODES] = {IRQ_NONE};
38
39 /* Get the target id for this processor. We rely on the constraint that the registers
40 * for PPI are read only and return only the current processor as the target.
41 * If this doesn't lead to a valid ID, we emit a warning and default to core 0.
42 */
infer_cpu_gic_id(int nirqs)43 BOOT_CODE static uint8_t infer_cpu_gic_id(int nirqs)
44 {
45 word_t i;
46 uint32_t target = 0;
47 for (i = 0; i < nirqs; i += 4) {
48 target = gic_dist->targets[i >> 2];
49 target |= target >> 16;
50 target |= target >> 8;
51 if (target) {
52 break;
53 }
54 }
55 if (!target) {
56 printf("Warning: Could not infer GIC interrupt target ID, assuming 0.\n");
57 target = BIT(0);
58 }
59 return target & 0xff;
60 }
61
dist_init(void)62 BOOT_CODE static void dist_init(void)
63 {
64 word_t i;
65 int nirqs = 32 * ((gic_dist->ic_type & 0x1f) + 1);
66 gic_dist->enable = 0;
67
68 for (i = 0; i < nirqs; i += 32) {
69 /* disable */
70 gic_dist->enable_clr[i >> 5] = IRQ_SET_ALL;
71 /* clear pending */
72 gic_dist->pending_clr[i >> 5] = IRQ_SET_ALL;
73 }
74
75 /* reset interrupts priority */
76 for (i = 32; i < nirqs; i += 4) {
77 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT)) {
78 gic_dist->priority[i >> 2] = 0x80808080;
79 } else {
80 gic_dist->priority[i >> 2] = 0;
81 }
82 }
83
84 /*
85 * reset int target to current cpu
86 * We query which id that the GIC uses for us and use that.
87 */
88 uint8_t target = infer_cpu_gic_id(nirqs);
89 for (i = 0; i < nirqs; i += 4) {
90 gic_dist->targets[i >> 2] = TARGET_CPU_ALLINT(target);
91 }
92
93 /* level-triggered, 1-N */
94 for (i = 64; i < nirqs; i += 32) {
95 gic_dist->config[i >> 5] = 0x55555555;
96 }
97
98 /* group 0 for secure; group 1 for non-secure */
99 for (i = 0; i < nirqs; i += 32) {
100 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT) && !config_set(CONFIG_PLAT_QEMU_ARM_VIRT)) {
101 gic_dist->security[i >> 5] = 0xffffffff;
102 } else {
103 gic_dist->security[i >> 5] = 0;
104 }
105 }
106 /* enable the int controller */
107 gic_dist->enable = 1;
108 }
109
cpu_iface_init(void)110 BOOT_CODE static void cpu_iface_init(void)
111 {
112 uint32_t i;
113
114 /* For non-Exynos4, the registers are banked per CPU, need to clear them */
115 gic_dist->enable_clr[0] = IRQ_SET_ALL;
116 gic_dist->pending_clr[0] = IRQ_SET_ALL;
117
118 /* put everything in group 0; group 1 if in hyp mode */
119 if (config_set(CONFIG_ARM_HYPERVISOR_SUPPORT) && !config_set(CONFIG_PLAT_QEMU_ARM_VIRT)) {
120 gic_dist->security[0] = 0xffffffff;
121 gic_dist->priority[0] = 0x80808080;
122 } else {
123 gic_dist->security[0] = 0;
124 gic_dist->priority[0] = 0x0;
125 }
126
127 /* clear any software generated interrupts */
128 for (i = 0; i < 16; i += 4) {
129 gic_dist->sgi_pending_clr[i >> 2] = IRQ_SET_ALL;
130 }
131
132 gic_cpuiface->icontrol = 0;
133 /* the write to priority mask is ignored if the kernel is
134 * in non-secure mode and the priority mask is already configured
135 * by secure mode software. the elfloader should config the
136 * interrupt routing properly to ensure that the hyp-mode kernel
137 * can get interrupts
138 */
139 gic_cpuiface->pri_msk_c = 0x000000f0;
140 gic_cpuiface->pb_c = 0x00000003;
141
142 i = gic_cpuiface->int_ack;
143 while ((i & IRQ_MASK) != IRQ_NONE) {
144 gic_cpuiface->eoi = i;
145 i = gic_cpuiface->int_ack;
146 }
147 gic_cpuiface->icontrol = 1;
148 }
149
setIRQTrigger(irq_t irq,bool_t trigger)150 void setIRQTrigger(irq_t irq, bool_t trigger)
151 {
152 /* in the gic_config, there is a 2 bit field for each irq,
153 * setting the most significant bit of this field makes the irq edge-triggered,
154 * while 0 indicates that it is level-triggered */
155 word_t index = IRQT_TO_IRQ(irq) / 16u;
156 word_t offset = (IRQT_TO_IRQ(irq) % 16u) * 2;
157 if (trigger) {
158 /* set the bit */
159 gic_dist->config[index] |= BIT(offset + 1);
160 } else {
161 gic_dist->config[index] &= ~BIT(offset + 1);
162 }
163 }
164
initIRQController(void)165 BOOT_CODE void initIRQController(void)
166 {
167 /* irqInvalid cannot correspond to a valid IRQ index into the irq state array */
168 assert(INT_STATE_ARRAY_SIZE < IRQT_TO_IRQ(irqInvalid));
169 dist_init();
170 }
171
cpu_initLocalIRQController(void)172 BOOT_CODE void cpu_initLocalIRQController(void)
173 {
174 cpu_iface_init();
175 }
176
177 #ifdef ENABLE_SMP_SUPPORT
178 /*
179 * 25-24: target lister filter
180 * 0b00 - send the ipi to the CPU interfaces specified in the CPU target list
181 * 0b01 - send the ipi to all CPU interfaces except the cpu interface.
182 * that requrested teh ipi
183 * 0b10 - send the ipi only to the CPU interface that requested the IPI.
184 * 0b11 - reserved
185 *.
186 * 23-16: CPU targets list
187 * each bit of CPU target list [7:0] refers to the corresponding CPU interface.
188 * 3-0: SGIINTID
189 * software generated interrupt id, from 0 to 15...
190 */
ipi_send_target(irq_t irq,word_t cpuTargetList)191 void ipi_send_target(irq_t irq, word_t cpuTargetList)
192 {
193 if (config_set(CONFIG_PLAT_TX2)) {
194 /* We need to swap the top 4 bits and the bottom 4 bits of the
195 * cpuTargetList since the A57 cores with logical core ID 0-3 are
196 * in cluster 1 and the Denver2 cores with logical core ID 4-5 are
197 * in cluster 0. */
198 cpuTargetList = ((cpuTargetList & 0xf) << 4) | ((cpuTargetList & 0xf0) >> 4);
199 }
200 gic_dist->sgi_control = (cpuTargetList << (GICD_SGIR_CPUTARGETLIST_SHIFT)) | (IRQT_TO_IRQ(
201 irq) << GICD_SGIR_SGIINTID_SHIFT);
202 }
203
204 /*
205 * Set CPU target for the interrupt if it's not a PPI
206 */
setIRQTarget(irq_t irq,seL4_Word target)207 void setIRQTarget(irq_t irq, seL4_Word target)
208 {
209 uint8_t targetList = 1 << target;
210 uint8_t *targets = (void *)(gic_dist->targets);
211 word_t hwIRQ = IRQT_TO_IRQ(irq);
212
213 /* Return early if PPI */
214 if (IRQ_IS_PPI(irq)) {
215 fail("PPI can't have designated target core\n");
216 return;
217 }
218 targets[hwIRQ] = targetList;
219 }
220 #endif /* ENABLE_SMP_SUPPORT */
221
222 #ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
223
224 #ifndef GIC_V2_VCPUCTRL_PPTR
225 #error GIC_V2_VCPUCTRL_PPTR must be defined for virtual memory access to the gic virtual cpu interface control
226 #else /* GIC_PL400_GICVCPUCTRL_PPTR */
227 volatile struct gich_vcpu_ctrl_map *gic_vcpu_ctrl =
228 (volatile struct gich_vcpu_ctrl_map *)(GIC_V2_VCPUCTRL_PPTR);
229 #endif /* GIC_PL400_GICVCPUCTRL_PPTR */
230
231 unsigned int gic_vcpu_num_list_regs;
232
233 #endif /* End of CONFIG_ARM_HYPERVISOR_SUPPORT */
234