Subversion Repositories AFRtranscoder

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 mjames 1
/**************************************************************************//**
2
 * @file     irq_ctrl_gic.c
3
 * @brief    Interrupt controller handling implementation for GIC
4
 * @version  V1.0.1
5
 * @date     9. April 2018
6
 ******************************************************************************/
7
/*
8
 * Copyright (c) 2017 ARM Limited. All rights reserved.
9
 *
10
 * SPDX-License-Identifier: Apache-2.0
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the License); you may
13
 * not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 * www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
20
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24
 
25
#include <stddef.h>
26
 
27
#include "RTE_Components.h"
28
#include CMSIS_device_header
29
 
30
#include "irq_ctrl.h"
31
 
32
#if defined(__GIC_PRESENT) && (__GIC_PRESENT == 1U)
33
 
34
/// Number of implemented interrupt lines
35
#ifndef IRQ_GIC_LINE_COUNT
36
#define IRQ_GIC_LINE_COUNT      (1020U)
37
#endif
38
 
39
static IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT] = { 0U };
40
static uint32_t     IRQ_ID0;
41
 
42
/// Initialize interrupt controller.
43
__WEAK int32_t IRQ_Initialize (void) {
44
  uint32_t i;
45
 
46
  for (i = 0U; i < IRQ_GIC_LINE_COUNT; i++) {
47
    IRQTable[i] = (IRQHandler_t)NULL;
48
  }
49
  GIC_Enable();
50
  return (0);
51
}
52
 
53
 
54
/// Register interrupt handler.
55
__WEAK int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler) {
56
  int32_t status;
57
 
58
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
59
    IRQTable[irqn] = handler;
60
    status =  0;
61
  } else {
62
    status = -1;
63
  }
64
 
65
  return (status);
66
}
67
 
68
 
69
/// Get the registered interrupt handler.
70
__WEAK IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn) {
71
  IRQHandler_t h;
72
 
73
  // Ignore CPUID field (software generated interrupts)
74
  irqn &= 0x3FFU;
75
 
76
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
77
    h = IRQTable[irqn];
78
  } else {
79
    h = (IRQHandler_t)0;
80
  }
81
 
82
  return (h);
83
}
84
 
85
 
86
/// Enable interrupt.
87
__WEAK int32_t IRQ_Enable (IRQn_ID_t irqn) {
88
  int32_t status;
89
 
90
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
91
    GIC_EnableIRQ ((IRQn_Type)irqn);
92
    status = 0;
93
  } else {
94
    status = -1;
95
  }
96
 
97
  return (status);
98
}
99
 
100
 
101
/// Disable interrupt.
102
__WEAK int32_t IRQ_Disable (IRQn_ID_t irqn) {
103
  int32_t status;
104
 
105
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
106
    GIC_DisableIRQ ((IRQn_Type)irqn);
107
    status = 0;
108
  } else {
109
    status = -1;
110
  }
111
 
112
  return (status);
113
}
114
 
115
 
116
/// Get interrupt enable state.
117
__WEAK uint32_t IRQ_GetEnableState (IRQn_ID_t irqn) {
118
  uint32_t enable;
119
 
120
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
121
    enable = GIC_GetEnableIRQ((IRQn_Type)irqn);
122
  } else {
123
    enable = 0U;
124
  }
125
 
126
  return (enable);
127
}
128
 
129
 
130
/// Configure interrupt request mode.
131
__WEAK int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode) {
132
  uint32_t val;
133
  uint8_t cfg;
134
  uint8_t secure;
135
  uint8_t cpu;
136
  int32_t status = 0;
137
 
138
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
139
    // Check triggering mode
140
    val = (mode & IRQ_MODE_TRIG_Msk);
141
 
142
    if (val == IRQ_MODE_TRIG_LEVEL) {
143
      cfg = 0x00U;
144
    } else if (val == IRQ_MODE_TRIG_EDGE) {
145
      cfg = 0x02U;
146
    } else {
147
      cfg = 0x00U;
148
      status = -1;
149
    }
150
 
151
    // Check interrupt type
152
    val = mode & IRQ_MODE_TYPE_Msk;
153
 
154
    if (val != IRQ_MODE_TYPE_IRQ) {
155
      status = -1;
156
    }
157
 
158
    // Check interrupt domain
159
    val = mode & IRQ_MODE_DOMAIN_Msk;
160
 
161
    if (val == IRQ_MODE_DOMAIN_NONSECURE) {
162
      secure = 0U;
163
    } else {
164
      // Check security extensions support
165
      val = GIC_DistributorInfo() & (1UL << 10U);
166
 
167
      if (val != 0U) {
168
        // Security extensions are supported
169
        secure = 1U;
170
      } else {
171
        secure = 0U;
172
        status = -1;
173
      }
174
    }
175
 
176
    // Check interrupt CPU targets
177
    val = mode & IRQ_MODE_CPU_Msk;
178
 
179
    if (val == IRQ_MODE_CPU_ALL) {
180
      cpu = 0xFFU;
181
    } else {
182
      cpu = val >> IRQ_MODE_CPU_Pos;
183
    }
184
 
185
    // Apply configuration if no mode error
186
    if (status == 0) {
187
      GIC_SetConfiguration((IRQn_Type)irqn, cfg);
188
      GIC_SetTarget       ((IRQn_Type)irqn, cpu);
189
 
190
      if (secure != 0U) {
191
        GIC_SetGroup ((IRQn_Type)irqn, secure);
192
      }
193
    }
194
  }
195
 
196
  return (status);
197
}
198
 
199
 
200
/// Get interrupt mode configuration.
201
__WEAK uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
202
  uint32_t mode;
203
  uint32_t val;
204
 
205
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
206
    mode = IRQ_MODE_TYPE_IRQ;
207
 
208
    // Get trigger mode
209
    val = GIC_GetConfiguration((IRQn_Type)irqn);
210
 
211
    if ((val & 2U) != 0U) {
212
      // Corresponding interrupt is edge triggered
213
      mode |= IRQ_MODE_TRIG_EDGE;
214
    } else {
215
      // Corresponding interrupt is level triggered
216
      mode |= IRQ_MODE_TRIG_LEVEL;
217
    }
218
 
219
    // Get interrupt CPU targets
220
    mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
221
 
222
  } else {
223
    mode = IRQ_MODE_ERROR;
224
  }
225
 
226
  return (mode);
227
}
228
 
229
 
230
/// Get ID number of current interrupt request (IRQ).
231
__WEAK IRQn_ID_t IRQ_GetActiveIRQ (void) {
232
  IRQn_ID_t irqn;
233
  uint32_t prio;
234
 
235
  /* Dummy read to avoid GIC 390 errata 801120 */
236
  GIC_GetHighPendingIRQ();
237
 
238
  irqn = GIC_AcknowledgePending();
239
 
240
  __DSB();
241
 
242
  /* Workaround GIC 390 errata 733075 (GIC-390_Errata_Notice_v6.pdf, 09-Jul-2014)  */
243
  /* The following workaround code is for a single-core system.  It would be       */
244
  /* different in a multi-core system.                                             */
245
  /* If the ID is 0 or 0x3FE or 0x3FF, then the GIC CPU interface may be locked-up */
246
  /* so unlock it, otherwise service the interrupt as normal.                      */
247
  /* Special IDs 1020=0x3FC and 1021=0x3FD are reserved values in GICv1 and GICv2  */
248
  /* so will not occur here.                                                       */
249
 
250
  if ((irqn == 0) || (irqn >= 0x3FE)) {
251
    /* Unlock the CPU interface with a dummy write to Interrupt Priority Register */
252
    prio = GIC_GetPriority((IRQn_Type)0);
253
    GIC_SetPriority ((IRQn_Type)0, prio);
254
 
255
    __DSB();
256
 
257
    if ((irqn == 0U) && ((GIC_GetIRQStatus ((IRQn_Type)irqn) & 1U) != 0U) && (IRQ_ID0 == 0U)) {
258
      /* If the ID is 0, is active and has not been seen before */
259
      IRQ_ID0 = 1U;
260
    }
261
    /* End of Workaround GIC 390 errata 733075 */
262
  }
263
 
264
  return (irqn);
265
}
266
 
267
 
268
/// Get ID number of current fast interrupt request (FIQ).
269
__WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
270
  return ((IRQn_ID_t)-1);
271
}
272
 
273
 
274
/// Signal end of interrupt processing.
275
__WEAK int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
276
  int32_t status;
277
  IRQn_Type irq = (IRQn_Type)irqn;
278
 
279
  irqn &= 0x3FFU;
280
 
281
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
282
    GIC_EndInterrupt (irq);
283
 
284
    if (irqn == 0) {
285
      IRQ_ID0 = 0U;
286
    }
287
 
288
    status = 0;
289
  } else {
290
    status = -1;
291
  }
292
 
293
  return (status);
294
}
295
 
296
 
297
/// Set interrupt pending flag.
298
__WEAK int32_t IRQ_SetPending (IRQn_ID_t irqn) {
299
  int32_t status;
300
 
301
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
302
    GIC_SetPendingIRQ ((IRQn_Type)irqn);
303
    status = 0;
304
  } else {
305
    status = -1;
306
  }
307
 
308
  return (status);
309
}
310
 
311
/// Get interrupt pending flag.
312
__WEAK uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
313
  uint32_t pending;
314
 
315
  if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
316
    pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
317
  } else {
318
    pending = 0U;
319
  }
320
 
321
  return (pending & 1U);
322
}
323
 
324
 
325
/// Clear interrupt pending flag.
326
__WEAK int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
327
  int32_t status;
328
 
329
  if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
330
    GIC_ClearPendingIRQ ((IRQn_Type)irqn);
331
    status = 0;
332
  } else {
333
    status = -1;
334
  }
335
 
336
  return (status);
337
}
338
 
339
 
340
/// Set interrupt priority value.
341
__WEAK int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
342
  int32_t status;
343
 
344
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
345
    GIC_SetPriority ((IRQn_Type)irqn, priority);
346
    status = 0;
347
  } else {
348
    status = -1;
349
  }
350
 
351
  return (status);
352
}
353
 
354
 
355
/// Get interrupt priority.
356
__WEAK uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
357
  uint32_t priority;
358
 
359
  if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
360
    priority = GIC_GetPriority ((IRQn_Type)irqn);
361
  } else {
362
    priority = IRQ_PRIORITY_ERROR;
363
  }
364
 
365
  return (priority);
366
}
367
 
368
 
369
/// Set priority masking threshold.
370
__WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
371
  GIC_SetInterfacePriorityMask (priority);
372
  return (0);
373
}
374
 
375
 
376
/// Get priority masking threshold
377
__WEAK uint32_t IRQ_GetPriorityMask (void) {
378
  return GIC_GetInterfacePriorityMask();
379
}
380
 
381
 
382
/// Set priority grouping field split point
383
__WEAK int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
384
  int32_t status;
385
 
386
  if (bits == IRQ_PRIORITY_Msk) {
387
    bits = 7U;
388
  }
389
 
390
  if (bits < 8U) {
391
    GIC_SetBinaryPoint (7U - bits);
392
    status = 0;
393
  } else {
394
    status = -1;
395
  }
396
 
397
  return (status);
398
}
399
 
400
 
401
/// Get priority grouping field split point
402
__WEAK uint32_t IRQ_GetPriorityGroupBits (void) {
403
  uint32_t bp;
404
 
405
  bp = GIC_GetBinaryPoint() & 0x07U;
406
 
407
  return (7U - bp);
408
}
409
 
410
#endif