1 // ----------------------------------------------------------
2 // GIC400 - Generic Interrupt Controller
3 //
4 // GIC Exercise
5 // ----------------------------------------------------------
6
7 #include "gic400_gic.h"
8
9 struct gic400_dist_if
10 {
11 volatile unsigned int GICD_CTLR; // +0x000 - RW - Distributor Control Register
12 const volatile unsigned int GICD_TYPRE; // +0x004 - RO - Interrupt Controller Type Register
13 const volatile unsigned int GICD_IIDR; // +0x008 - RO - Distributor Implementer Identification Register
14
15 const volatile unsigned int padding0[29];
16
17 volatile unsigned int GICD_IGROUPR[32]; // +0x080 - RW - Interrupt Groupt Registers (Security Registers in GICv1)
18
19 volatile unsigned int GICD_ISENABLER[32]; // +0x100 - RW - Interrupt Set-Enable Registers
20 volatile unsigned int GICD_ICENABLER[32]; // +0x180 - RW - Interrupt Clear-Enable Registers
21 volatile unsigned int GICD_ISPENDR[32]; // +0x200 - RW - Interrupt Set-Pending Registers
22 volatile unsigned int GICD_ICPENDR[32]; // +0x280 - RW - Interrupt Clear-Pending Registers
23 volatile unsigned int GICD_ISACTIVER[32]; // +0x300 - RW - Interrupt Set-Active Register
24 volatile unsigned int GICD_ICACTIVER[32]; // +0x380 - RW - Interrupt Clear-Active Register
25
26 volatile unsigned char GICD_IPRIORITYR[1024]; // +0x400 - RW - Interrupt Priority Registers
27 volatile unsigned int GICD_ITARGETSR[256]; // +0x800 - RW - Interrupt Processor Targets Registers
28 volatile unsigned int GICD_ICFGR[64]; // +0xC00 - RW - Interrupt Configuration Registers
29
30 const volatile unsigned int padding2[128];
31
32 volatile unsigned int GICD_SGIR; // +0xF00 - WO - Software Generated Interrupt Register
33
34 };
35
36 struct gic400_physical_cpu_if
37 {
38 volatile unsigned int GICC_CTLR; // +0x000 - RW - CPU Interface Control Register
39 volatile unsigned int GICC_PMR; // +0x004 - RW - Interrupt Priority Mask Register
40 volatile unsigned int GICC_BPR; // +0x008 - RW - Binary Point Register
41 const volatile unsigned int GICC_IAR; // +0x00C - RO - Interrupt Acknowledge Register
42 volatile unsigned int GICC_EOIR; // +0x010 - WO - End of Interrupt Register
43 const volatile unsigned int GICC_RPR; // +0x014 - RO - Running Priority Register
44 const volatile unsigned int GICC_HPPIR; // +0x018 - RO - Highest Pending Interrupt Register
45 volatile unsigned int GICC_ABPR; // +0x01C - RW - Aliased Binary Point Register
46 const volatile unsigned int GICC_AIAR; // +0x020 - RO - Aliased Interrupt Acknowledge Register
47 volatile unsigned int GICC_AEOIR; // +0x024 - WO - Aliased End of Interrupt Register
48 const volatile unsigned int GICC_AHPPIR; // +0x028 - RO - Aliased Highest Pending Interrupt Register
49
50 const volatile unsigned int padding0[52];
51
52 const volatile unsigned int GICC_IIDR; // +0x0FC - RO - CPU Interface Identification Register
53 };
54
55 struct gic400_dist_if* gic_dist;
56 struct gic400_physical_cpu_if* gic_cpu;
57
58
59 // ------------------------------------------------------------
60
setGICAddr(void * dist,void * cpu)61 void setGICAddr(void* dist, void* cpu)
62 {
63 gic_dist = (struct gic400_dist_if*)dist;
64 gic_cpu = (struct gic400_physical_cpu_if*)cpu;
65 return;
66 }
67
68 // ------------------------------------------------------------
69
70 // Global enable of the Interrupt Distributor
enableGIC(void)71 void enableGIC(void)
72 {
73 gic_dist->GICD_CTLR = 3;
74 return;
75 }
76
77 // Global disable of the Interrupt Distributor
disableGIC(void)78 void disableGIC(void)
79 {
80 gic_dist->GICD_CTLR = 0;
81 return;
82 }
83
84 // ------------------------------------------------------------
85
86 // Enables the interrupt source number ID
enableIntID(unsigned int ID)87 void enableIntID(unsigned int ID)
88 {
89 unsigned int bank;
90
91 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
92 ID = ID & 0x1f; // ... and which bit within the register
93
94 ID = 1 << ID; // Move a '1' into the correct bit position
95
96 gic_dist->GICD_ISENABLER[bank] = ID;
97
98 return;
99 }
100
101 // Disables the interrupt source number ID
disableIntID(unsigned int ID)102 void disableIntID(unsigned int ID)
103 {
104 unsigned int bank;
105
106 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
107 ID = ID & 0x1f; // ... and which bit within the register
108
109 ID = 1 << ID; // Move a '1' into the correct bit position
110
111 gic_dist->GICD_ICENABLER[bank] = ID;
112
113 return;
114 }
115
116 // ------------------------------------------------------------
117
118 // Sets the priority of the specified ID
setIntPriority(unsigned int ID,unsigned int priority)119 void setIntPriority(unsigned int ID, unsigned int priority)
120 {
121 if (ID > 1020) // Check ID in range
122 return;
123
124 // The priority registers allows byte accesses
125 // meaning using a char array we can directly
126 // reference the correct entry
127 gic_dist->GICD_IPRIORITYR[ID] = priority;
128
129 return;
130 }
131
132 // Returns the priority of the specified ID
getIntPriority(unsigned int ID)133 unsigned int getIntPriority(unsigned int ID)
134 {
135 if (ID > 1020) // Check ID in range
136 return 0;
137
138 return gic_dist->GICD_IPRIORITYR[ID];
139 }
140
141 // ------------------------------------------------------------
142
143 // Sets the target CPUs of the specified ID
144 // For 'target' use one of the above defines
setIntTarget(unsigned int ID,unsigned int target)145 void setIntTarget(unsigned int ID, unsigned int target)
146 {
147 unsigned int bank, tmp;
148
149 target = target & 0xFF; // Target field is 8-bits, mask off unused bit
150 bank = ID/4; // There are 4 IDs per register, need to work out which register to access
151 ID = ID & 0x3; // ... and which field within the register
152 ID = ID * 8; // Convert from which field to a bit offset (8-bits per field)
153
154 target = target << ID; // Move prioity value into correct bit position
155
156 tmp = gic_dist->GICD_ITARGETSR[bank]; // Read the current value in the register
157 tmp = tmp & ~(0xFF << ID); // Blank out the field holding the value we're modifying
158 tmp = tmp | target; // OR in the new target
159 gic_dist->GICD_ITARGETSR[bank] = tmp;
160
161 return;
162 }
163
164 // Returns the target CPUs of the specified ID
getIntTarget(unsigned int ID)165 unsigned int getIntTarget(unsigned int ID)
166 {
167 unsigned int bank, tmp;
168
169 bank = ID/4; // There are 4 IDs per register, need to work out which register to access
170 ID = ID & 0x3; // ... and which field within the register
171 ID = ID * 8; // Convert from which field to a bit offset (8-bits per field)
172
173 tmp = gic_dist->GICD_ITARGETSR[bank];
174
175 tmp = tmp >> ID; // Shift desired field to bit position 0
176 tmp = tmp & 0xFF; // Mask off the other bits
177
178 return tmp;
179 }
180
181 // ----------------------------------------------------------
182
183 // Configures the specified ID as being level or edge triggered
configureSPI(unsigned int ID,unsigned int conf)184 void configureSPI(unsigned int ID, unsigned int conf)
185 {
186 unsigned int bank, tmp;
187
188 conf = conf & 0x3; // Mask out unused bits
189
190 bank = ID/16; // There are 16 IDs per register, need to work out which register to access
191 ID = ID & 0xF; // ... and which field within the register
192 ID = ID * 2; // Convert from which field to a bit offset (2-bits per field)
193
194 conf = conf << ID; // Move configuration value into correct bit position
195
196 tmp = gic_dist-> GICD_ICFGR[bank]; // Read current vlase
197 tmp = tmp & ~(0x3 << ID); // Clear the bits for the specified field
198 tmp = tmp | conf; // OR in new configuration
199 gic_dist-> GICD_ICFGR[bank] = tmp; // Write updated value back
200
201 return;
202 }
203
204 // ----------------------------------------------------------
205
206 // Sets the pending bit of the specified ID
setIntPending(unsigned int ID)207 void setIntPending(unsigned int ID)
208 {
209 unsigned int bank;
210
211 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
212 ID = ID & 0x1f; // ... and which bit within the register
213
214 ID = 1 << ID; // Move a '1' into the correct bit position
215
216 gic_dist->GICD_ISPENDR[bank] = ID;
217
218 return;
219 }
220
221 // Clears the pending bit of the specified ID
clearIntPending(unsigned int ID)222 void clearIntPending(unsigned int ID)
223 {
224 unsigned int bank;
225
226 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
227 ID = ID & 0x1f; // ... and which bit within the register
228
229 ID = 1 << ID; // Move a '1' into the correct bit position
230
231 gic_dist->GICD_ICPENDR[bank] = ID;
232
233 return;
234 }
235
236 // Returns the value of the status bit of the specifed ID
getIntPending(unsigned int ID)237 unsigned int getIntPending(unsigned int ID)
238 {
239 unsigned int bank, tmp;
240
241 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
242 ID = ID & 0x1f; // ... and which bit within the register
243
244 tmp = gic_dist->GICD_ICPENDR[bank]; // Read the register containing the ID we are interested in
245 tmp = tmp >> ID; // Shift the status bit for specified ID to position 0
246 tmp = tmp & 0x1; // Mask off the rest of the register
247
248 return tmp;
249 }
250
251 // ------------------------------------------------------------
252
253 // Send a software generate interrupt
sendSGI(unsigned int ID,unsigned int cpu_list,unsigned int filter_list,unsigned int SATT)254 void sendSGI(unsigned int ID, unsigned int cpu_list, unsigned int filter_list, unsigned int SATT)
255 {
256 // Ensure unused bits are clear, and shift into correct bit position
257 ID = ID & 0xF;
258 SATT = (SATT & 0x1) << 15;
259 cpu_list = (cpu_list & 0xFF) << 16;
260 filter_list = (filter_list & 0x3) << 24;
261
262 // Combine fields
263 ID = ID | SATT | cpu_list | filter_list;
264
265 gic_dist->GICD_SGIR = ID;
266
267 return;
268 }
269
270 // ------------------------------------------------------------
271
272 // Sets the specified ID as secure
makeIntGroup0(unsigned int ID)273 void makeIntGroup0(unsigned int ID)
274 {
275 unsigned int bank, tmp;
276
277 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
278 ID = ID & 0x1f; // ... and which bit within the register
279
280 ID = 1 << ID; // Move a '1' into the correct bit position
281 ID = ~ID; // Invert to get mask
282
283 tmp = gic_dist->GICD_IGROUPR[bank]; // Read current value
284 tmp = tmp & ID;
285 gic_dist->GICD_IGROUPR[bank] = tmp;
286
287 return;
288 }
289
290 // Set the specified ID as non-secure
makeIntGroup1(unsigned int ID)291 void makeIntGroup1(unsigned int ID)
292 {
293 unsigned int bank, tmp;
294
295 bank = ID/32; // There are 32 IDs per register, need to work out which register to access
296 ID = ID & 0x1f; // ... and which bit within the register
297
298 ID = 1 << ID; // Move a '1' into the correct bit position
299
300 tmp = gic_dist->GICD_IGROUPR[bank]; // Read current value
301 tmp = tmp | ID; // Or with bit mask to set the bit
302 gic_dist->GICD_IGROUPR[bank] = tmp; // Write-back
303 }
304
305 // Returns the security of the specified ID
getIntGroup(unsigned int ID)306 unsigned int getIntGroup(unsigned int ID)
307 {
308 // TBD
309 return 0;
310 }
311
312 // ------------------------------------------------------------
313 // CPU Interface functions
314 // ------------------------------------------------------------
315
316 // Enables the CPU interface
317 // Must been done one each core seperately
enableCPUInterface(void)318 void enableCPUInterface(void)
319 {
320 unsigned int tmp;
321
322 tmp = gic_cpu->GICC_CTLR;
323 tmp = tmp | 0x1; // Set bit 0
324 gic_cpu->GICC_CTLR = tmp;
325 }
326
327 // Enables the group 1 (non-secure) CPU interface
328 // This function can only be called from the Secure world
329 // Must been done one each core seperately
enableNonSecureCPUInterface(void)330 void enableNonSecureCPUInterface(void)
331 {
332 unsigned int tmp;
333
334 tmp = gic_cpu->GICC_CTLR;
335 tmp = tmp | 0x2; // Set bit 1
336 gic_cpu->GICC_CTLR = tmp;
337 }
338
339 // Disables the processor interface
disableCPUInterface(void)340 void disableCPUInterface(void)
341 {
342 unsigned int tmp;
343
344 tmp = gic_cpu->GICC_CTLR;
345 tmp = tmp & 0xFFFFFFFFE; // Clear bit 0
346 gic_cpu->GICC_CTLR = tmp;
347 }
348
349 // Enables the sending of secure interrupts as FIQs
enableSecureFIQs(void)350 void enableSecureFIQs(void)
351 {
352 unsigned int tmp;
353
354 tmp = gic_cpu->GICC_CTLR;
355 tmp = tmp | 0x8; // Set bit 3
356 gic_cpu->GICC_CTLR = tmp;
357 }
358
359 // Disables the sending of secure interrupts as FIQs
disableSecureFIQs(void)360 void disableSecureFIQs(void)
361 {
362 unsigned int tmp;
363
364 tmp = gic_cpu->GICC_CTLR;
365 tmp = tmp | 0xFFFFFFFF7; // Clear bit 3
366 gic_cpu->GICC_CTLR = tmp;
367 }
368
369 // Returns the value of the Interrupt Acknowledge Register
readIntAck(void)370 unsigned int readIntAck(void)
371 {
372 return gic_cpu->GICC_IAR;
373 }
374
375 // Writes ID to the End Of Interrupt register
writeEOI(unsigned int ID)376 void writeEOI(unsigned int ID)
377 {
378 gic_cpu->GICC_EOIR = ID;
379 return;
380 }
381
382 // Returns the value of the Aliased Interrupt Acknowledge Register
readAliasedIntAck(void)383 unsigned int readAliasedIntAck(void)
384 {
385 return gic_cpu->GICC_AIAR;
386 }
387
388 // Writes ID to the Aliased End Of Interrupt register
writeAliasedEOI(unsigned int ID)389 void writeAliasedEOI(unsigned int ID)
390 {
391 gic_cpu->GICC_AEOIR = ID;
392 return;
393 }
394
395 // Sets the Priority mask register for the core run on
396 // The reset value masks ALL interrupts!
setPriorityMask(unsigned int priority)397 void setPriorityMask(unsigned int priority)
398 {
399 gic_cpu->GICC_PMR = (priority & 0xFF);
400 return;
401 }
402
403 // Sets the Binary Point Register for the core run on
setBinaryPoint(unsigned int priority)404 void setBinaryPoint(unsigned int priority)
405 {
406 gic_cpu->GICC_BPR = (priority & 0xFF);
407 return;
408 }
409
410 // Sets the Aliased Binary Point Register for the core run on
setAliasedBinaryPoint(unsigned int priority)411 void setAliasedBinaryPoint(unsigned int priority)
412 {
413 gic_cpu->GICC_ABPR = (priority & 0xFF);
414 return;
415 }
416
417 // ------------------------------------------------------------
418 // End of gic400_gic.c
419 // ------------------------------------------------------------
420