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