source: rtems/bsps/arm/shared/irq/irq-gic.c @ ebf0f8f

Last change on this file since ebf0f8f was ebf0f8f, checked in by Kinsey Moore <kinsey.moore@…>, on Aug 16, 2019 at 7:14:33 PM

bsps/arm/shared: Add GICv3 implementation

This adds support for the GICv3 interrupt controller along with the
redistributor to control SGIs and PPIs which wasn't present in GICv2
implementations. GICv3 implementations only optionally support
memory-mapped GICC interface interaction and require system register
access be implemented, so the GICC interface is accessed only
through system registers.

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2013, 2019 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <bsp/arm-gic.h>
16
17#include <rtems/score/armv4.h>
18
19#include <libcpu/arm-cp15.h>
20
21#include <bsp/irq.h>
22#include <bsp/irq-generic.h>
23#include <bsp/start.h>
24
25#define GIC_CPUIF ((volatile gic_cpuif *) BSP_ARM_GIC_CPUIF_BASE)
26
27#define PRIORITY_DEFAULT 127
28
29/*
30 * The following variants
31 *
32 *  - GICv1 with Security Extensions,
33 *  - GICv2 without Security Extensions, or
34 *  - within Secure processor mode
35 *
36 * have the ability to assign group 0 or 1 to individual interrupts.  Group
37 * 0 interrupts can be configured to raise an FIQ exception.  This enables
38 * the use of NMIs with respect to RTEMS.
39 *
40 * BSPs can enable this feature with the BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
41 * define.  Use arm_gic_irq_set_group() to change the group of an
42 * interrupt (default group is 1, if BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0 is
43 * defined).
44 */
45#ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
46#define DIST_ICDDCR (GIC_DIST_ICDDCR_ENABLE_GRP_1 | GIC_DIST_ICDDCR_ENABLE)
47#define CPUIF_ICCICR \
48  (GIC_CPUIF_ICCICR_CBPR | GIC_CPUIF_ICCICR_FIQ_EN \
49    | GIC_CPUIF_ICCICR_ACK_CTL | GIC_CPUIF_ICCICR_ENABLE_GRP_1 \
50    | GIC_CPUIF_ICCICR_ENABLE)
51#else
52#define DIST_ICDDCR GIC_DIST_ICDDCR_ENABLE
53#define CPUIF_ICCICR GIC_CPUIF_ICCICR_ENABLE
54#endif
55
56void bsp_interrupt_dispatch(void)
57{
58  volatile gic_cpuif *cpuif = GIC_CPUIF;
59  uint32_t icciar = cpuif->icciar;
60  rtems_vector_number vector = GIC_CPUIF_ICCIAR_ACKINTID_GET(icciar);
61  rtems_vector_number spurious = 1023;
62
63  if (vector != spurious) {
64    uint32_t psr = _ARMV4_Status_irq_enable();
65
66    bsp_interrupt_handler_dispatch(vector);
67
68    _ARMV4_Status_restore(psr);
69
70    cpuif->icceoir = icciar;
71  }
72}
73
74void bsp_interrupt_vector_enable(rtems_vector_number vector)
75{
76  volatile gic_dist *dist = ARM_GIC_DIST;
77
78  bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
79
80  gic_id_enable(dist, vector);
81}
82
83void bsp_interrupt_vector_disable(rtems_vector_number vector)
84{
85  volatile gic_dist *dist = ARM_GIC_DIST;
86
87  bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
88
89  gic_id_disable(dist, vector);
90}
91
92static inline uint32_t get_id_count(volatile gic_dist *dist)
93{
94  uint32_t id_count = GIC_DIST_ICDICTR_IT_LINES_NUMBER_GET(dist->icdictr);
95
96  id_count = 32 * (id_count + 1);
97  id_count = id_count <= 1020 ? id_count : 1020;
98
99  return id_count;
100}
101
102static void enable_fiq(void)
103{
104#ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
105  rtems_interrupt_level level;
106
107  rtems_interrupt_local_disable(level);
108  level &= ~ARM_PSR_F;
109  rtems_interrupt_local_enable(level);
110#endif
111}
112
113rtems_status_code bsp_interrupt_facility_initialize(void)
114{
115  volatile gic_cpuif *cpuif = GIC_CPUIF;
116  volatile gic_dist *dist = ARM_GIC_DIST;
117  uint32_t id_count = get_id_count(dist);
118  uint32_t id;
119
120  arm_cp15_set_exception_handler(
121    ARM_EXCEPTION_IRQ,
122    _ARMV4_Exception_interrupt
123  );
124
125  for (id = 0; id < id_count; id += 32) {
126#ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
127    dist->icdigr[id / 32] = 0xffffffff;
128#endif
129    dist->icdicer[id / 32] = 0xffffffff;
130  }
131
132  for (id = 0; id < id_count; ++id) {
133    gic_id_set_priority(dist, id, PRIORITY_DEFAULT);
134  }
135
136  for (id = 32; id < id_count; ++id) {
137    gic_id_set_targets(dist, id, 0x01);
138  }
139
140  cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff);
141  cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0);
142  cpuif->iccicr = CPUIF_ICCICR;
143
144  dist->icddcr = GIC_DIST_ICDDCR_ENABLE_GRP_1 | GIC_DIST_ICDDCR_ENABLE;
145
146  enable_fiq();
147  return RTEMS_SUCCESSFUL;
148}
149
150#ifdef RTEMS_SMP
151BSP_START_TEXT_SECTION void arm_gic_irq_initialize_secondary_cpu(void)
152{
153  volatile gic_cpuif *cpuif = GIC_CPUIF;
154  volatile gic_dist *dist = ARM_GIC_DIST;
155
156  while ((dist->icddcr & GIC_DIST_ICDDCR_ENABLE) == 0) {
157    /* Wait */
158  }
159
160#ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
161  dist->icdigr[0] = 0xffffffff;
162#endif
163
164  cpuif->iccpmr = GIC_CPUIF_ICCPMR_PRIORITY(0xff);
165  cpuif->iccbpr = GIC_CPUIF_ICCBPR_BINARY_POINT(0x0);
166  cpuif->iccicr = CPUIF_ICCICR;
167
168  enable_fiq();
169}
170#endif
171
172rtems_status_code arm_gic_irq_set_priority(
173  rtems_vector_number vector,
174  uint8_t priority
175)
176{
177  rtems_status_code sc = RTEMS_SUCCESSFUL;
178
179  if (bsp_interrupt_is_valid_vector(vector)) {
180    volatile gic_dist *dist = ARM_GIC_DIST;
181
182    gic_id_set_priority(dist, vector, priority);
183  } else {
184    sc = RTEMS_INVALID_ID;
185  }
186
187  return sc;
188}
189
190rtems_status_code arm_gic_irq_get_priority(
191  rtems_vector_number vector,
192  uint8_t *priority
193)
194{
195  rtems_status_code sc = RTEMS_SUCCESSFUL;
196
197  if (bsp_interrupt_is_valid_vector(vector)) {
198    volatile gic_dist *dist = ARM_GIC_DIST;
199
200    *priority = gic_id_get_priority(dist, vector);
201  } else {
202    sc = RTEMS_INVALID_ID;
203  }
204
205  return sc;
206}
207
208rtems_status_code arm_gic_irq_set_group(
209  rtems_vector_number vector,
210  gic_group group
211)
212{
213  rtems_status_code sc = RTEMS_SUCCESSFUL;
214
215  if (bsp_interrupt_is_valid_vector(vector)) {
216    volatile gic_dist *dist = ARM_GIC_DIST;
217
218    gic_id_set_group(dist, vector, group);
219  } else {
220    sc = RTEMS_INVALID_ID;
221  }
222
223  return sc;
224}
225
226rtems_status_code arm_gic_irq_get_group(
227  rtems_vector_number vector,
228  gic_group *group
229)
230{
231  rtems_status_code sc = RTEMS_SUCCESSFUL;
232
233  if (bsp_interrupt_is_valid_vector(vector)) {
234    volatile gic_dist *dist = ARM_GIC_DIST;
235
236    *group = gic_id_get_group(dist, vector);
237  } else {
238    sc = RTEMS_INVALID_ID;
239  }
240
241  return sc;
242}
243
244void bsp_interrupt_set_affinity(
245  rtems_vector_number vector,
246  const Processor_mask *affinity
247)
248{
249  volatile gic_dist *dist = ARM_GIC_DIST;
250  uint8_t targets = (uint8_t) _Processor_mask_To_uint32_t(affinity, 0);
251
252  gic_id_set_targets(dist, vector, targets);
253}
254
255void bsp_interrupt_get_affinity(
256  rtems_vector_number vector,
257  Processor_mask *affinity
258)
259{
260  volatile gic_dist *dist = ARM_GIC_DIST;
261  uint8_t targets = gic_id_get_targets(dist, vector);
262
263  _Processor_mask_From_uint32_t(affinity, targets, 0);
264}
265
266void arm_gic_trigger_sgi(
267  rtems_vector_number vector,
268  arm_gic_irq_software_irq_target_filter filter,
269  uint8_t targets
270)
271{
272  volatile gic_dist *dist = ARM_GIC_DIST;
273
274  dist->icdsgir = GIC_DIST_ICDSGIR_TARGET_LIST_FILTER(filter)
275    | GIC_DIST_ICDSGIR_CPU_TARGET_LIST(targets)
276#ifdef BSP_ARM_GIC_ENABLE_FIQ_FOR_GROUP_0
277    | GIC_DIST_ICDSGIR_NSATT
278#endif
279    | GIC_DIST_ICDSGIR_SGIINTID(vector);
280}
Note: See TracBrowser for help on using the repository browser.