|
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of the License "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\nkernsmp\arm\ncirq.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalTechnology |
|
21 */ |
|
22 |
|
23 #include "nk_priv.h" |
|
24 #include "nk_plat.h" |
|
25 #include <nk_irq.h> |
|
26 #include <arm.h> |
|
27 #include <arm_gic.h> |
|
28 #include <arm_scu.h> |
|
29 #include <arm_tmr.h> |
|
30 |
|
31 #ifdef _DEBUG |
|
32 #define DMEMDUMP(base,size) DbgMemDump((TLinAddr)base,size) |
|
33 void DbgMemDump(TLinAddr aBase, TInt aSize) |
|
34 { |
|
35 TInt off; |
|
36 const TUint8* p=(const TUint8*)aBase; |
|
37 NKern::Lock(); |
|
38 for (off=0; off<aSize; off+=16, p+=16) |
|
39 { |
|
40 DEBUGPRINT("%08x: %02x %02x %02x %02x %02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x", |
|
41 p, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], |
|
42 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); |
|
43 } |
|
44 NKern::Unlock(); |
|
45 } |
|
46 #else |
|
47 #define DMEMDUMP(base,size) |
|
48 #endif |
|
49 |
|
50 /****************************************************************************** |
|
51 * ARM Generic Interrupt Controller |
|
52 ******************************************************************************/ |
|
53 |
|
54 class ArmGic |
|
55 { |
|
56 public: |
|
57 static void Enable(TInt aIndex); |
|
58 static void Disable(TInt aIndex); |
|
59 static TBool IsEnabled(TInt aIndex); |
|
60 static void SetPending(TInt aIndex); |
|
61 static void ClearPending(TInt aIndex); |
|
62 static TBool IsPending(TInt aIndex); |
|
63 static TBool IsActive(TInt aIndex); |
|
64 static TBool SetNonSecure(TInt aIndex, TBool aNonSecure); |
|
65 static TUint32 Priority(TInt aIndex); |
|
66 static TUint32 SetPriority(TInt aIndex, TUint32 aPri); |
|
67 static TUint32 Dest(TInt aIndex); |
|
68 static TUint32 ModifyDest(TInt aIndex, TUint32 aClear, TUint32 aSet); |
|
69 static TUint32 Config(TInt aIndex); |
|
70 static TUint32 ModifyConfig(TInt aIndex, TUint32 aClear, TUint32 aSet); |
|
71 |
|
72 static void Dump(); |
|
73 static void DumpCpuIfc(); |
|
74 public: |
|
75 static TSpinLock ArmGicLock; |
|
76 static TInt LSPI; |
|
77 static TInt Domains; |
|
78 static TInt NumCpus; |
|
79 static TInt NumLines; |
|
80 static TUint32 PriMask; |
|
81 static TUint32 PriSpc; |
|
82 static TUint32 MinPri; |
|
83 }; |
|
84 |
|
85 TSpinLock ArmGic::ArmGicLock(TSpinLock::EOrderBTrace); |
|
86 TInt ArmGic::LSPI; |
|
87 TInt ArmGic::Domains; |
|
88 TInt ArmGic::NumCpus; |
|
89 TInt ArmGic::NumLines; |
|
90 TUint32 ArmGic::PriMask; |
|
91 TUint32 ArmGic::PriSpc; |
|
92 TUint32 ArmGic::MinPri; |
|
93 |
|
94 void ArmGic::Enable(TInt aIndex) |
|
95 { |
|
96 TUint32 mask = 1u << (aIndex&31); |
|
97 GIC_DIST.iEnableSet[aIndex>>5] = mask; |
|
98 arm_dsb(); |
|
99 } |
|
100 |
|
101 void ArmGic::Disable(TInt aIndex) |
|
102 { |
|
103 TUint32 mask = 1u << (aIndex&31); |
|
104 GIC_DIST.iEnableClear[aIndex>>5] = mask; |
|
105 arm_dsb(); |
|
106 } |
|
107 |
|
108 TBool ArmGic::IsEnabled(TInt aIndex) |
|
109 { |
|
110 TUint32 mask = 1u << (aIndex&31); |
|
111 return GIC_DIST.iEnableSet[aIndex>>5] & mask; |
|
112 } |
|
113 |
|
114 void ArmGic::SetPending(TInt aIndex) |
|
115 { |
|
116 TUint32 mask = 1u << (aIndex&31); |
|
117 GIC_DIST.iPendingSet[aIndex>>5] = mask; |
|
118 arm_dsb(); |
|
119 } |
|
120 |
|
121 void ArmGic::ClearPending(TInt aIndex) |
|
122 { |
|
123 TUint32 mask = 1u << (aIndex&31); |
|
124 GIC_DIST.iPendingClear[aIndex>>5] = mask; |
|
125 arm_dsb(); |
|
126 } |
|
127 |
|
128 TBool ArmGic::IsPending(TInt aIndex) |
|
129 { |
|
130 TUint32 mask = 1u << (aIndex&31); |
|
131 return GIC_DIST.iPendingSet[aIndex>>5] & mask; |
|
132 } |
|
133 |
|
134 TBool ArmGic::IsActive(TInt aIndex) |
|
135 { |
|
136 TUint32 mask = 1u << (aIndex&31); |
|
137 return GIC_DIST.iActive[aIndex>>5] & mask; |
|
138 } |
|
139 |
|
140 TUint32 ArmGic::Dest(TInt aIndex) |
|
141 { |
|
142 TUint32 reg = GIC_DIST.iTarget[aIndex>>2]; |
|
143 reg >>= ((aIndex&3)<<3); |
|
144 reg &= 0xff; |
|
145 return reg; |
|
146 } |
|
147 |
|
148 TUint32 ArmGic::ModifyDest(TInt aIndex, TUint32 aClear, TUint32 aSet) |
|
149 { |
|
150 aClear &= 0xff; |
|
151 aSet &= 0xff; |
|
152 TInt shift = (aIndex&3)<<3; |
|
153 aClear <<= shift; |
|
154 aSet <<= shift; |
|
155 volatile TUint32& reg = GIC_DIST.iTarget[aIndex>>2]; |
|
156 TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); |
|
157 TUint32 old = reg; |
|
158 reg = (old &~ aClear) | aSet; |
|
159 arm_dsb(); |
|
160 __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); |
|
161 old >>= shift; |
|
162 return old & 0xff; |
|
163 } |
|
164 |
|
165 TUint32 ArmGic::Config(TInt aIndex) |
|
166 { |
|
167 TInt shift = (aIndex&15)<<1; |
|
168 TUint32 x = GIC_DIST.iConfig[aIndex>>4]; |
|
169 x >>= shift; |
|
170 return x & 3; |
|
171 } |
|
172 |
|
173 TUint32 ArmGic::ModifyConfig(TInt aIndex, TUint32 aClear, TUint32 aSet) |
|
174 { |
|
175 aClear &= 3; |
|
176 aSet &= 3; |
|
177 TInt shift = (aIndex&15)<<1; |
|
178 aClear <<= shift; |
|
179 aSet <<= shift; |
|
180 volatile TUint32& reg = GIC_DIST.iConfig[aIndex>>4]; |
|
181 TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); |
|
182 TUint32 old = reg; |
|
183 reg = (old &~ aClear) | aSet; |
|
184 arm_dsb(); |
|
185 __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); |
|
186 old >>= shift; |
|
187 return old & 3; |
|
188 } |
|
189 |
|
190 TBool ArmGic::SetNonSecure(TInt aIndex, TBool aNonSecure) |
|
191 { |
|
192 TUint32 mask = 1u << (aIndex & 31); |
|
193 volatile TUint32& reg = GIC_DIST.iIntSec[aIndex>>5]; |
|
194 TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); |
|
195 TUint32 old = reg; |
|
196 reg = aNonSecure ? (old | mask) : (old &~ mask); |
|
197 arm_dsb(); |
|
198 __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); |
|
199 return old & mask; |
|
200 } |
|
201 |
|
202 TUint32 ArmGic::Priority(TInt aIndex) |
|
203 { |
|
204 TInt shift = (aIndex&3)<<3; |
|
205 TUint32 x = GIC_DIST.iPriority[aIndex>>2]; |
|
206 x >>= shift; |
|
207 return x & 0xff; |
|
208 } |
|
209 |
|
210 TUint32 ArmGic::SetPriority(TInt aIndex, TUint32 aPri) |
|
211 { |
|
212 aPri &= 0xff; |
|
213 TInt shift = (aIndex&3)<<3; |
|
214 TUint32 clear = 0xffu << shift; |
|
215 aPri <<= shift; |
|
216 volatile TUint32& reg = GIC_DIST.iPriority[aIndex>>2]; |
|
217 TInt irq = __SPIN_LOCK_IRQSAVE(ArmGicLock); |
|
218 TUint32 old = reg; |
|
219 reg = (old &~ clear) | aPri; |
|
220 arm_dsb(); |
|
221 __SPIN_UNLOCK_IRQRESTORE(ArmGicLock, irq); |
|
222 old >>= shift; |
|
223 return old & 0xff; |
|
224 } |
|
225 |
|
226 void ArmGic::Dump() |
|
227 { |
|
228 #ifdef KBOOT |
|
229 __KTRACE_OPT(KBOOT,DEBUGPRINT("GIC iCtrl=%08x iType=%08x", GIC_DIST.iCtrl, GIC_DIST.iType)); |
|
230 TInt n = ArmGic::NumLines; |
|
231 TInt i; |
|
232 for (i=0; i<n; i++) |
|
233 { |
|
234 TUint32 cfg = Config(i); |
|
235 TUint32 pri = Priority(i); |
|
236 TUint32 dest = Dest(i); |
|
237 TUint32 enabled = IsEnabled(i) ? 1 : 0; |
|
238 TUint32 pending = IsPending(i) ? 1 : 0; |
|
239 TUint32 active = IsActive(i) ? 1 : 0; |
|
240 const char* cat = (i<16) ? "SW" : (i<32) ? "PP" : "SP"; |
|
241 __KTRACE_OPT(KBOOT,DEBUGPRINT("%3d: %2s cfg=%1d pri=%02x dest=%02x E%1d P%1d A%1d", |
|
242 i, cat, cfg, pri, dest, enabled, pending, active)); |
|
243 } |
|
244 #endif |
|
245 } |
|
246 |
|
247 void ArmGic::DumpCpuIfc() |
|
248 { |
|
249 #ifdef KBOOT |
|
250 GicCpuIfc& C = GIC_CPU_IFC; |
|
251 __KTRACE_OPT(KBOOT,DEBUGPRINT("IFC iCtrl=%08x iPriMask=%08x iBinaryPoint=%08x", C.iCtrl, C.iPriMask, C.iBinaryPoint)); |
|
252 __KTRACE_OPT(KBOOT,DEBUGPRINT("IFC Running=%08x HighestP=%08x", C.iRunningPri, C.iHighestPending)); |
|
253 #endif |
|
254 } |
|
255 |
|
256 |
|
257 void NIrq::HwEoi() |
|
258 { |
|
259 if (iX && iX->iEoiFn) |
|
260 (*iX->iEoiFn)(this); |
|
261 else |
|
262 { |
|
263 GIC_CPU_IFC.iEoi = iVector; |
|
264 |
|
265 #if defined(SMP_CRAZY_INTERRUPTS) && !defined(__STANDALONE_NANOKERNEL__) |
|
266 // change the target CPU for the next Interrupt |
|
267 if ((TInt)TheSuperPage().KernelConfigFlags() & EKernelConfigSMPCrazyInterrupts) |
|
268 { |
|
269 TInt cpu = NKern::CurrentCpu() + 1; |
|
270 if(cpu >= NKern::NumberOfCpus()) |
|
271 cpu = 0; |
|
272 ArmGic::ModifyDest(iVector, 0xffu, 1u << cpu); |
|
273 } |
|
274 else |
|
275 arm_dsb(); |
|
276 |
|
277 #else |
|
278 arm_dsb(); |
|
279 #endif |
|
280 } |
|
281 } |
|
282 |
|
283 void NIrq::HwEnable() |
|
284 { |
|
285 if (iX && iX->iEnableFn) |
|
286 (*iX->iEnableFn)(this); |
|
287 else |
|
288 { |
|
289 ArmGic::Enable(iVector); |
|
290 } |
|
291 } |
|
292 |
|
293 void NIrq::HwDisable() |
|
294 { |
|
295 if (iX && iX->iDisableFn) |
|
296 (*iX->iDisableFn)(this); |
|
297 else |
|
298 { |
|
299 ArmGic::Disable(iVector); |
|
300 } |
|
301 } |
|
302 |
|
303 void NIrq::HwSetCpu(TInt aCpu) |
|
304 { |
|
305 if (iX && iX->iSetCpuFn) |
|
306 (*iX->iSetCpuFn)(this, 1u<<aCpu); |
|
307 else |
|
308 { |
|
309 ArmGic::ModifyDest(iVector, 0xffu, 1u<<aCpu); |
|
310 } |
|
311 } |
|
312 |
|
313 void NIrq::HwSetCpuMask(TUint32 aMask) |
|
314 { |
|
315 if (iX && iX->iSetCpuFn) |
|
316 (*iX->iSetCpuFn)(this, aMask); |
|
317 else |
|
318 { |
|
319 ArmGic::ModifyDest(iVector, 0xffu, aMask); |
|
320 } |
|
321 } |
|
322 |
|
323 void NIrq::HwInit() |
|
324 { |
|
325 if (iX && iX->iInitFn) |
|
326 (*iX->iInitFn)(this); |
|
327 else |
|
328 { |
|
329 __KTRACE_OPT(KBOOT,DEBUGPRINT("NIrq %02x HwInit", iIndex)); |
|
330 TUint32 clear = E_GicDistICfgEdge; |
|
331 TUint32 set = 0; |
|
332 if (!(iStaticFlags & ELevel)) |
|
333 set = E_GicDistICfgEdge; |
|
334 ArmGic::ModifyConfig(iVector, clear, set); |
|
335 } |
|
336 } |
|
337 |
|
338 TBool NIrq::HwPending() |
|
339 { |
|
340 if (iX && iX->iPendingFn) |
|
341 return (*iX->iPendingFn)(this); |
|
342 return ArmGic::IsPending(iVector) || ArmGic::IsActive(iVector); |
|
343 } |
|
344 |
|
345 void NIrq::HwWaitCpus() |
|
346 { |
|
347 if (iX && iX->iWaitFn) |
|
348 (*iX->iWaitFn)(this); |
|
349 } |
|
350 |
|
351 void NIrq::HwInit0() |
|
352 { |
|
353 __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit0")); |
|
354 |
|
355 // Need to set up addresses of GIC_DIST, GIC_CPU_IFC, SCU and LOCAL_TIMER |
|
356 |
|
357 GicDistributor& D = GIC_DIST; |
|
358 GicCpuIfc& C = GIC_CPU_IFC; |
|
359 D.iCtrl = 0; |
|
360 C.iCtrl = 0; |
|
361 arm_dsb(); |
|
362 TUint32 type = D.iType; |
|
363 __KTRACE_OPT(KBOOT, DEBUGPRINT("GIC iType = %08x", type)); |
|
364 ArmGic::LSPI = (type & E_GicDistType_LSPIMask) >> E_GicDistType_LSPIShift; |
|
365 ArmGic::Domains = (type & E_GicDistType_Domains) ? 2 : 1; |
|
366 ArmGic::NumCpus = ((type & E_GicDistType_CPUNMask) >> E_GicDistType_CPUNShift) + 1; |
|
367 ArmGic::NumLines = ((type & E_GicDistType_ITMask) + 1) << 5; |
|
368 __KTRACE_OPT(KBOOT, DEBUGPRINT("GIC LSPI=%d Domains=%d NumCpus=%d NumLines=%d", |
|
369 ArmGic::LSPI, ArmGic::Domains, ArmGic::NumCpus, ArmGic::NumLines)); |
|
370 TInt i; |
|
371 for (i=0; i<32; ++i) |
|
372 D.iEnableClear[i] = 0xffffffffu; // disable all interrupts |
|
373 arm_dsb(); |
|
374 for (i=0; i<32; ++i) |
|
375 D.iPendingClear[i] = 0xffffffffu; // clear any pending interrupts |
|
376 arm_dsb(); |
|
377 D.iPriority[0] = 0xffffffffu; |
|
378 ArmGic::PriMask = D.iPriority[0] & 0xffu; |
|
379 ArmGic::PriSpc = (~ArmGic::PriMask + 1) & 0xffu; |
|
380 ArmGic::MinPri = ArmGic::PriMask - ArmGic::PriSpc; |
|
381 __KTRACE_OPT(KBOOT, DEBUGPRINT("PriMask=%02x PriSpc=%02x MinPri=%02x", ArmGic::PriMask, ArmGic::PriSpc, ArmGic::MinPri)); |
|
382 TUint32 x = ArmGic::MinPri; |
|
383 x |= (x<<8); |
|
384 x |= (x<<16); |
|
385 for (i=0; i<256; ++i) |
|
386 D.iPriority[i] = x; // set all interrupts to minimum active priority |
|
387 x = 0x01010101u; |
|
388 for (i=0; i<256; ++i) |
|
389 D.iTarget[i] = x; // set all interrupts to target this CPU |
|
390 x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) |
|
391 D.iConfig[0] = x; // set config for 0-15 |
|
392 x = 0x28000000u; // 31=0b00, 30=29=0b10 |
|
393 D.iConfig[1] = x; // set config for 16-31 |
|
394 x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) |
|
395 for (i=2; i<64; ++i) |
|
396 D.iConfig[i] = x; // set default value for other interrupts |
|
397 arm_dsb(); |
|
398 ArmGic::Dump(); |
|
399 } |
|
400 |
|
401 void NIrq::HwInit1() |
|
402 { |
|
403 __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit1")); |
|
404 |
|
405 // elevate priority of CRASH_IPI to highest level |
|
406 ArmGic::SetPriority(CRASH_IPI_VECTOR, 0); |
|
407 |
|
408 GicDistributor& D = GIC_DIST; |
|
409 GicCpuIfc& C = GIC_CPU_IFC; |
|
410 C.iCtrl = 0; |
|
411 C.iPriMask = ArmGic::PriMask; // unmask all interrupts |
|
412 C.iBinaryPoint = 0; |
|
413 arm_dsb(); |
|
414 C.iCtrl = E_GicDistCtrl_Enable; // enable this CPU's interrupt controller interface |
|
415 arm_dsb(); |
|
416 D.iCtrl = E_GicDistCtrl_Enable; // enable the global interrupt distributor |
|
417 arm_dsb(); |
|
418 |
|
419 // Enable timeslice timer interrupt |
|
420 ArmLocalTimer& T = LOCAL_TIMER; |
|
421 T.iTimerCtrl = 0; |
|
422 T.iTimerIntStatus = E_ArmTmrIntStatus_Event; |
|
423 ArmGic::ClearPending(TIMESLICE_VECTOR); |
|
424 arm_dsb(); |
|
425 ArmGic::Enable(TIMESLICE_VECTOR); |
|
426 arm_dsb(); |
|
427 T.iTimerLoad = KMaxTUint32; // timer wraps to 0xffffffff after reaching 0 |
|
428 arm_dsb(); |
|
429 T.iTimerCount = (TUint32)KMaxTInt32; // timer starts at 0x7fffffff (initial thread doesn't timeslice) |
|
430 arm_dsb(); |
|
431 |
|
432 ArmGic::DumpCpuIfc(); |
|
433 } |
|
434 |
|
435 void NIrq::HwInit2AP() |
|
436 { |
|
437 __KTRACE_OPT(KBOOT, DEBUGPRINT("NIrq::HwInit2AP")); |
|
438 |
|
439 // Must set up interrupts 0-31 separately for each CPU |
|
440 GicDistributor& D = GIC_DIST; |
|
441 TInt i; |
|
442 TUint32 x = ArmGic::MinPri; |
|
443 x |= (x<<8); |
|
444 x |= (x<<16); |
|
445 for (i=0; i<32; ++i) |
|
446 D.iPriority[i] = x; // set all interrupts to minimum active priority |
|
447 x = 0xAAAAAAAAu; // config value for SW interrupts (rising edge, N-N) |
|
448 D.iConfig[0] = x; // set config for 0-15 |
|
449 x = 0x28000000u; // 31=0b00, 30=29=0b10 |
|
450 D.iConfig[1] = x; // set config for 16-31 |
|
451 arm_dsb(); |
|
452 ArmGic::Dump(); |
|
453 |
|
454 // elevate priority of CRASH_IPI to highest level |
|
455 ArmGic::SetPriority(CRASH_IPI_VECTOR, 0); |
|
456 |
|
457 GicCpuIfc& C = GIC_CPU_IFC; |
|
458 C.iCtrl = 0; |
|
459 C.iPriMask = ArmGic::PriMask; // unmask all interrupts |
|
460 C.iBinaryPoint = 0; |
|
461 arm_dsb(); |
|
462 C.iCtrl = E_GicDistCtrl_Enable; |
|
463 arm_dsb(); |
|
464 |
|
465 // Enable timeslice timer interrupt |
|
466 ArmLocalTimer& T = LOCAL_TIMER; |
|
467 T.iTimerCtrl = 0; |
|
468 T.iTimerIntStatus = E_ArmTmrIntStatus_Event; |
|
469 ArmGic::ClearPending(TIMESLICE_VECTOR); |
|
470 arm_dsb(); |
|
471 ArmGic::Enable(TIMESLICE_VECTOR); |
|
472 arm_dsb(); |
|
473 T.iTimerLoad = KMaxTUint32; // timer wraps to 0xffffffff after reaching 0 |
|
474 arm_dsb(); |
|
475 T.iTimerCount = (TUint32)KMaxTInt32; // timer starts at 0x7fffffff (initial thread doesn't timeslice) |
|
476 arm_dsb(); |
|
477 |
|
478 ArmGic::DumpCpuIfc(); |
|
479 } |
|
480 |