]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/arm/bsp/exynos/pic-arm-gic-exynos.cpp
update
[l4.git] / kernel / fiasco / src / kern / arm / bsp / exynos / pic-arm-gic-exynos.cpp
1 INTERFACE:
2 #include "gic.h"
3
4 //-------------------------------------------------------------------------
5 IMPLEMENTATION [arm && pic_gic && exynos]:
6
7 class Mgr_exynos : public Irq_mgr
8 {
9 protected:
10   struct Chip_block
11   {
12     unsigned sz;
13     Irq_chip_gen *chip;
14   };
15
16   void calc_nr_irq()
17   {
18     _nr_irqs = 0;
19     for (unsigned i = 0; i < _nr_blocks; ++i)
20       _nr_irqs += _block[i].sz;
21   }
22
23 public:
24   unsigned nr_irqs() const { return _nr_irqs; }
25   unsigned nr_msis() const { return 0; }
26
27 protected:
28   unsigned _nr_blocks;
29   unsigned _nr_irqs;
30   Chip_block *_block;
31 };
32
33
34 //-------------------------------------------------------------------------
35 IMPLEMENTATION [arm && pic_gic && exynos]:
36
37 #include <cstring>
38 #include <cstdio>
39
40 #include "assert.h"
41 #include "boot_alloc.h"
42 #include "config.h"
43 #include "initcalls.h"
44 #include "io.h"
45 #include "irq_chip.h"
46 #include "irq_chip_generic.h"
47 #include "irq_mgr.h"
48 #include "gic.h"
49 #include "kmem.h"
50 #include "mmio_register_block.h"
51 #include "warn.h"
52
53 #include "platform.h"
54
55
56 class Gpio_eint_chip : public Irq_chip_gen, private Mmio_register_block
57 {
58 private:
59   unsigned offs(Mword pin) const { return (pin >> 3) * 4; }
60
61 public:
62   Gpio_eint_chip(Mword gpio_base, unsigned num_irqs)
63     : Irq_chip_gen(num_irqs), _gpio_base(gpio_base)
64   {}
65
66   void mask(Mword pin)
67   { Io::set<Mword>(1 << (pin & 7), _gpio_base + MASK + offs(pin)); }
68
69   void ack(Mword pin)
70   { Io::set<Mword>(1 << (pin & 7), _gpio_base + PEND + offs(pin)); }
71
72   void mask_and_ack(Mword pin) { mask(pin); ack(pin); }
73
74   void unmask(Mword pin)
75   { Io::clear<Mword>(1 << (pin & 7), _gpio_base + MASK + offs(pin)); }
76
77   void set_cpu(Mword, Cpu_number) {}
78   unsigned set_mode(Mword pin, unsigned m)
79   {
80     unsigned v;
81
82     m &= ~1;
83
84     switch (m)
85     {
86       default: m = Irq_base::Trigger_level | Irq_base::Polarity_low;
87                /* Fall-through */
88       case Irq_base::Trigger_level | Irq_base::Polarity_low:  v = 0; break;
89       case Irq_base::Trigger_level | Irq_base::Polarity_high: v = 1; break;
90       case Irq_base::Trigger_edge  | Irq_base::Polarity_low:  v = 2; break;
91       case Irq_base::Trigger_edge  | Irq_base::Polarity_high: v = 3; break;
92       case Irq_base::Trigger_edge  | Irq_base::Polarity_both: v = 4; break;
93     };
94
95     Mword a = _gpio_base + INTCON + offs(pin);
96     pin = pin % 8;
97     v <<= pin * 4;
98     Io::write<Mword>((Io::read<Mword>(a) & ~(7 << (pin * 4))) | v, a);
99
100     return m;
101   }
102   unsigned pending() { return Io::read<Mword>(_gpio_base + 0xb08); }
103
104 private:
105   enum {
106     INTCON = 0x700,
107     MASK   = 0x900,
108     PEND   = 0xa00,
109   };
110   Mword _gpio_base;
111 };
112
113 class Gpio_wakeup_chip : public Irq_chip_gen, private Mmio_register_block
114 {
115 private:
116   unsigned offs(Mword pin) const { return (pin >> 3) * 4; }
117
118 public:
119   explicit Gpio_wakeup_chip(Address physbase)
120   : Irq_chip_gen(32),
121     Mmio_register_block(Kmem::mmio_remap(physbase))
122   {}
123
124   void mask(Mword pin)
125   { modify<Mword>(1 << (pin & 7), 0, MASK + offs(pin)); }
126
127   void ack(Mword pin)
128   { modify<Mword>(1 << (pin & 7), 0, PEND + offs(pin)); }
129
130   void mask_and_ack(Mword pin) { mask(pin); ack(pin); }
131
132   void unmask(Mword pin)
133   { modify<Mword>(0, 1 << (pin & 7), MASK + offs(pin)); }
134   void set_cpu(Mword, Cpu_number) {}
135
136   unsigned set_mode(Mword pin, unsigned m)
137   {
138     unsigned v;
139     m &= ~1;
140
141     switch (m)
142     {
143       default: m = Irq_base::Trigger_level | Irq_base::Polarity_low;
144                /* Fall-through */
145       case Irq_base::Trigger_level | Irq_base::Polarity_low:  v = 0; break;
146       case Irq_base::Trigger_level | Irq_base::Polarity_high: v = 1; break;
147       case Irq_base::Trigger_edge  | Irq_base::Polarity_low:  v = 2; break;
148       case Irq_base::Trigger_edge  | Irq_base::Polarity_high: v = 3; break;
149       case Irq_base::Trigger_edge  | Irq_base::Polarity_both: v = 4; break;
150     };
151
152     Mword a = INTCON + offs(pin);
153     pin = pin % 8;
154     v <<= pin * 4;
155     modify<Mword>(v, 7UL << (pin * 4), a);
156
157     return m;
158   }
159
160   unsigned pending01() const // debug only
161   {
162     return read<Unsigned8>(PEND + 0) | (static_cast<unsigned>(read<Unsigned8>(PEND +  4)) << 8);
163   }
164
165   unsigned pending23() const
166   {
167     return read<Unsigned8>(PEND + 8) | (static_cast<unsigned>(read<Unsigned8>(PEND + 12)) << 8);
168   }
169
170 private:
171   enum {
172     INTCON = 0xe00,
173     FLTCON = 0xe80,
174     MASK   = 0xf00,
175     PEND   = 0xf40,
176   };
177 };
178
179 class Combiner_chip : public Irq_chip_gen, private Mmio_register_block
180 {
181 public:
182   enum
183   {
184     Enable_set    = 0,
185     Enable_clear  = 4,
186     Status        = 12,
187   };
188
189   enum
190   {
191     No_pending = ~0UL,
192   };
193
194   Mword offset(unsigned irq) const { return (irq >> 2) * 0x10; }
195
196   static unsigned shift(int irq)
197   { return (irq % 4) * 8; }
198
199   static Mword bytemask(int irq)
200   { return 0xffUL << shift(irq); }
201
202   Mword status(int irq) const
203   { return read<Mword>(offset(irq) + Status) & bytemask(irq); }
204
205   void mask(Mword i)
206   { write<Mword>(1UL << (i & 31), offset(i / 8) + Enable_clear); }
207
208   void mask_and_ack(Mword i)
209   { Combiner_chip::mask(i); }
210
211   void ack(Mword) {}
212
213   void set_cpu(Mword, Cpu_number) {}
214
215   unsigned set_mode(Mword, unsigned)
216   { return Irq_base::Trigger_level; }
217
218   void unmask(Mword i)
219   { write<Mword>(1UL << (i & 31), offset(i / 8) + Enable_set); }
220
221   void init_irq(int irq) const
222   { write<Mword>(bytemask(irq), offset(irq) + Enable_clear); }
223
224   Unsigned32 pending(unsigned cnr)
225   {
226     unsigned v = status(cnr) >> shift(cnr);
227     for (unsigned i = 0; i < 8; ++i)
228       if (v & (1 << i))
229         return (cnr * 8) + i;
230     // use __builtin_clz...
231
232     return No_pending;
233   }
234
235   int num_combiner_chips() const
236   {
237     if (Platform::is_4210())
238       return Platform::gic_int() ? 54 : 16;
239     if (Platform::is_4412())
240       return 20;
241     if (Platform::is_5250())
242       return 32;
243     assert(0);
244     return 0;
245   }
246
247   Combiner_chip()
248   : Irq_chip_gen(num_combiner_chips() * 8),
249     Mmio_register_block(Kmem::mmio_remap(Mem_layout::Irq_combiner_phys_base))
250   {
251     // 0..39, 51, 53
252     if (Platform::gic_int())
253       {
254         for (int i = 0; i < 40; ++i)
255           init_irq(i);
256         init_irq(51);
257         init_irq(53);
258       }
259     else
260       {
261         const int num = num_combiner_chips();
262         for (int i = 0; i < num; ++i)
263           init_irq(i);
264       }
265   }
266 };
267
268 // ------------
269
270 class Gpio_cascade_wu01_irq : public Irq_base
271 {
272 public:
273   explicit Gpio_cascade_wu01_irq(Gpio_wakeup_chip *gc, unsigned pin)
274   : _wu_gpio(gc), _pin(pin)
275   { set_hit(&handler_wrapper<Gpio_cascade_wu01_irq>); }
276
277   void switch_mode(unsigned) {}
278
279   void handle(Upstream_irq const *u)
280   {
281     // checking pending reg as a debug thing
282     if (!(_wu_gpio->pending01() & (1 << _pin)))
283       WARN("WU-GPIO not pending %d\n", _pin);
284
285     Upstream_irq ui(this, u);
286     _wu_gpio->irq(_pin)->hit(&ui);
287   }
288
289 private:
290   Gpio_wakeup_chip *_wu_gpio;
291   unsigned _pin;
292 };
293
294
295 class Gpio_cascade_wu23_irq : public Irq_base
296 {
297 public:
298   explicit Gpio_cascade_wu23_irq(Gpio_wakeup_chip *gc)
299   : _wu_gpio(gc)
300   { set_hit(&handler_wrapper<Gpio_cascade_wu23_irq>); }
301
302   void switch_mode(unsigned) {}
303
304 private:
305   Gpio_wakeup_chip *_wu_gpio;
306 };
307
308 PUBLIC
309 void
310 Gpio_cascade_wu23_irq::handle(Upstream_irq const *u)
311 {
312   unsigned mask = _wu_gpio->pending23();
313   Upstream_irq ui(this, u);
314   for (unsigned p = 0; p < 16; ++p)
315     if ((1 << p) & mask)
316       {
317         _wu_gpio->irq(p + 16)->hit(&ui);
318         break;
319       }
320 }
321
322 class Gpio_cascade_xab_irq : public Irq_base
323 {
324 public:
325   explicit Gpio_cascade_xab_irq(Gpio_eint_chip *g, unsigned special = 0)
326   : _eint_gc(g), _special(special)
327   { set_hit(&handler_wrapper<Gpio_cascade_xab_irq>); }
328
329   void switch_mode(unsigned) {}
330
331 private:
332   Gpio_eint_chip *_eint_gc;
333   unsigned _special;
334 };
335
336 PUBLIC
337 void
338 Gpio_cascade_xab_irq::handle(Upstream_irq const *u)
339 {
340   Mword p = _eint_gc->pending();
341   Upstream_irq ui(this, u);
342   if (1)
343     {
344       int grp = (p >> 3) & 0x1f;
345       int pin = p & 7;
346
347       if (_special == 1)
348         {
349           if (grp > 7)
350             grp += 5;
351         }
352       else if (_special == 2)
353         grp += 2;
354
355       _eint_gc->irq((grp - 1) * 8 + pin)->hit(&ui);
356     }
357   else
358     _eint_gc->irq(p - 8)->hit(&ui);
359 }
360
361 // ------------
362 class Combiner_cascade_irq : public Irq_base
363 {
364 public:
365   Combiner_cascade_irq(unsigned nr, Combiner_chip *chld)
366   : _combiner_nr(nr), _child(chld)
367   { set_hit(&handler_wrapper<Combiner_cascade_irq>); }
368
369   void switch_mode(unsigned) {}
370   unsigned irq_nr_base() const { return _combiner_nr * 8; }
371
372 private:
373   unsigned _combiner_nr;
374   Combiner_chip *_child;
375 };
376
377 PUBLIC
378 void
379 Combiner_cascade_irq::handle(Upstream_irq const *u)
380 {
381   Unsigned32 num = _child->pending(_combiner_nr);
382   Upstream_irq ui(this, u);
383
384   if (num != Combiner_chip::No_pending)
385     _child->irq(num)->hit(&ui);
386 }
387
388 // ------------------------------------------------------------------------
389 IMPLEMENTATION [arm && pic_gic && exynos]:
390
391 IMPLEMENT inline
392 Pic::Status Pic::disable_all_save()
393 { return 0; }
394
395 IMPLEMENT inline
396 void Pic::restore_all(Status)
397 {}
398
399 // ------------------------------------------------------------------------
400 IMPLEMENTATION [exynos4 && !exynos_extgic]:
401
402 class Mgr_int : public Mgr_exynos
403 {
404 public:
405
406   Irq chip(Mword irqnum) const
407   {
408     Mword origirq = irqnum;
409
410     for (unsigned i = 0; i < _nr_blocks; ++i)
411       {
412         if (irqnum < _block[i].sz)
413           return Irq(_block[i].chip, irqnum);
414
415         irqnum -= _block[i].sz;
416       }
417
418     printf("KERNEL: exynos-irq: Invalid irqnum=%ld\n", origirq);
419     return Irq();
420   }
421
422 private:
423   Gic *_gic;
424   Combiner_chip *_cc;
425   Gpio_wakeup_chip *_wu_gc;
426   Gpio_eint_chip *_ei_gc1, *_ei_gc2;
427 };
428
429 PUBLIC
430 Mgr_int::Mgr_int()
431 {
432   _gic = Pic::gic.construct(Kmem::mmio_remap(Mem_layout::Gic_cpu_int_phys_base),
433                             Kmem::mmio_remap(Mem_layout::Gic_dist_int_phys_base));
434
435   _cc     = new Boot_object<Combiner_chip>();
436   _wu_gc  = new Boot_object<Gpio_wakeup_chip>(Kmem::Gpio2_phys_base);
437   _ei_gc1 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio1_phys_base));
438   _ei_gc2 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio2_phys_base));
439
440   // Combiners
441   for (unsigned i = 0; i < 40; ++i)
442     {
443       _gic->alloc(new Boot_object<Combiner_cascade_irq>(i, _cc), i + 32);
444       _gic->unmask(i + 32);
445     }
446   _gic->alloc(new Boot_object<Combiner_cascade_irq>(51, _cc), 51 + 32);
447   _gic->unmask(51 + 32);
448   _gic->alloc(new Boot_object<Combiner_cascade_irq>(53, _cc), 53 + 32);
449   _gic->unmask(53 + 32);
450
451   // GPIO-wakeup0-3 goes to GIC
452   _gic->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 0), 72); _gic->unmask(72);
453   _gic->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 1), 73); _gic->unmask(73);
454   _gic->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 2), 74); _gic->unmask(74);
455   _gic->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 3), 75); _gic->unmask(75);
456
457   // GPIO-wakeup4-7 -> comb37:0-3
458   for (unsigned i = 0; i < 4; ++i)
459     {
460       _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 4 + i), 8 * 37 + i);
461       _cc->unmask(8 * 37 + i);
462     }
463
464   // GPIO-wakeup8-15 -> COMB:38:0-7
465   for (unsigned i = 0; i < 8; ++i)
466     {
467       _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 8 + i), 8 * 38 + i);
468       _cc->unmask(8 * 38 + i);
469     }
470
471   // GPIO-wakeup16-31: COMP:39:0
472   _cc->alloc(new Boot_object<Gpio_cascade_wu23_irq>(_wu_gc), 8 * 39 + 0);
473   _cc->unmask(8 * 39 + 0);
474
475   // xa
476   _cc->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc1), 8 * 24 + 1);
477   _cc->unmask(8 * 24 + 1);
478
479   // xb
480   _cc->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc2), 8 * 24 + 0);
481   _cc->unmask(8 * 24 + 0);
482
483   static Chip_block soc[] = {
484     { 96,                _gic },
485     { 54 * 8,            _cc },
486     { 32,                _wu_gc },
487     { 16 * 8,            _ei_gc1 },
488     { (29 - 21 + 1) * 8, _ei_gc2 },
489   };
490
491   _block = soc;
492   _nr_blocks = sizeof(soc) / sizeof(soc[0]);
493
494   calc_nr_irq();
495 }
496
497
498 PUBLIC
499 void
500 Mgr_int::set_cpu(Mword irqnum, Cpu_number cpu) const
501 {
502   // this handles only the MCT_L[01] timers
503   if (   irqnum == 379  // MCT_L1: Combiner 35:3
504       || irqnum == 504) // MCT_L0: Combiner 51:0
505     _gic->set_cpu(32 + (irqnum - 96) / 8, cpu);
506   else
507     WARNX(Warning, "IRQ%ld: ignoring CPU setting (%d).\n",
508           irqnum, cxx::int_value<Cpu_number>(cpu));
509 }
510
511 IMPLEMENT static FIASCO_INIT
512 void Pic::init()
513 {
514   Irq_mgr::mgr = new Boot_object<Mgr_int>();
515 }
516
517 PUBLIC static
518 void Pic::init_ap(Cpu_number)
519 {
520   gic->init_ap();
521 }
522
523 // ------------------------------------------------------------------------
524 INTERFACE [exynos4 && exynos_extgic]:
525
526 #include "gic.h"
527 #include "per_cpu_data.h"
528 #include "platform.h"
529
530 EXTENSION class Pic
531 {
532 public:
533   static Per_cpu_ptr<Static_object<Gic> > gic;
534 };
535
536 // ------------------------------------------------------------------------
537 IMPLEMENTATION [exynos4 && exynos_extgic]:
538
539 #include "cpu.h"
540
541 Per_cpu_ptr<Static_object<Gic> > Pic::gic;
542
543 class Mgr_ext : public Mgr_exynos
544 {
545 public:
546   Irq chip(Mword irqnum) const
547   {
548     Mword origirq = irqnum;
549
550     for (unsigned i = 0; i < _nr_blocks; ++i)
551       {
552         if (irqnum < _block[i].sz)
553           {
554             if (i == 0) // some special handling in GIC block
555               if (!Platform::is_4412())
556                 if (irqnum == 80 && Config::Max_num_cpus > 1) // MCT_L1 goes to CPU1
557                   return Irq(_gic.cpu(Cpu_number(1)), irqnum);
558
559             return Irq(_block[i].chip, irqnum);
560           }
561
562         irqnum -= _block[i].sz;
563       }
564
565     printf("KERNEL: exynos-irq: Invalid irqnum=%ld\n", origirq);
566     return Irq();
567   }
568
569 private:
570   friend void irq_handler();
571   friend class Pic;
572   static Per_cpu<Static_object<Gic> > _gic;
573   Combiner_chip *_cc;
574   Gpio_wakeup_chip *_wu_gc;
575   Gpio_eint_chip *_ei_gc1, *_ei_gc2;
576   //Gpio_eint_chip *_ei_gc3, *_ei_gc4;
577 };
578
579 DEFINE_PER_CPU Per_cpu<Static_object<Gic> > Mgr_ext::_gic;
580
581 PUBLIC
582 Mgr_ext::Mgr_ext()
583 {
584   Gic *g = _gic.cpu(Cpu_number(0)).construct(
585       Kmem::mmio_remap(Mem_layout::Gic_cpu_ext_cpu0_phys_base),
586       Kmem::mmio_remap(Mem_layout::Gic_dist_ext_cpu0_phys_base));
587
588   _cc = new Boot_object<Combiner_chip>();
589
590   _wu_gc = new Boot_object<Gpio_wakeup_chip>(Kmem::Gpio2_phys_base);
591   _ei_gc1 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio1_phys_base), 18 * 8);
592   _ei_gc2 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio2_phys_base), 14 * 8);
593
594   // Combiners
595   for (unsigned i = 0; i < 16; ++i)
596     {
597       g->alloc(new Boot_object<Combiner_cascade_irq>(i, _cc), i + 32);
598       g->unmask(i + 32);
599     }
600
601   if (Platform::is_4412())
602     {
603       g->alloc(new Boot_object<Combiner_cascade_irq>(16, _cc), 139); g->unmask(139);
604       g->alloc(new Boot_object<Combiner_cascade_irq>(17, _cc), 140); g->unmask(140);
605       g->alloc(new Boot_object<Combiner_cascade_irq>(18, _cc), 80);  g->unmask(80);
606       g->alloc(new Boot_object<Combiner_cascade_irq>(19, _cc), 74);  g->unmask(74);
607     }
608
609   // GPIO-wakeup0-15 goes to GIC
610   for (unsigned i = 0; i < 16; ++i)
611     {
612       g->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, i), i + 48);
613       g->unmask(i + 48);
614     }
615
616   // GPIO-wakeup16-31: GIC:32+32
617   g->alloc(new Boot_object<Gpio_cascade_wu23_irq>(_wu_gc), 64);
618   g->unmask(64);
619
620   // xa GIC:32+47
621   g->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc1, Platform::is_4412() ? 1 : 0), 79);
622   g->unmask(79);
623
624   // xb GIC:32+46
625   g->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc2, Platform::is_4412() ? 2 : 0), 78);
626   g->unmask(78);
627
628
629   // 4210
630   //  - part1: ext-int 0x700: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
631   //  - part2: ext-int 0x700: 21, 22, 23, 24, 25, 26, 27, 28, 29
632   //                   0xe00: wu1, wu2, wu3, wu4
633   //  - part3: nix
634
635   static Chip_block soc4210[] = {
636     { 160,               _gic.cpu(Cpu_number(0)) },
637     { 16 * 8,            _cc },
638     { 32,                _wu_gc },
639     { 16 * 8,            _ei_gc1 },
640     { (29 - 21 + 1) * 8, _ei_gc2 },
641   };
642
643   // 4412
644   //  - part1: ext-int 0x700: 1, 2, 3, 4, 5, 6, 7, 13, 14, 15, 16, 21, 22
645   //  - part2: ext-int 0x700: 23, 24, 25, 26, 27, 28, 29, 8, 9, 10, 11, 12
646   //                   0xe00: 40, 41, 42, 43
647   //  - part3: ext-int 0x700: 50
648   //  - part4: ext-int 0x700: 30, 31, 32, 33, 34
649
650   static Chip_block soc4412[] = {
651     { 160,               _gic.cpu(Cpu_number(0)) },
652     { 20 * 8,            _cc },
653     {  4 * 8,            _wu_gc },
654     { 18 * 8,            _ei_gc1 },
655     { 14 * 8,            _ei_gc2 },
656     //{  1 * 8,            _ei_gc3 }, // Do not know upstream IRQ-num :(
657     //{  5 * 8,            _ei_gc4 }, // Do not know upstream IRQ-num :(
658   };
659
660   if (Platform::is_4412())
661     {
662       _block = soc4412;
663       _nr_blocks = sizeof(soc4412) / sizeof(soc4412[0]);
664     }
665   else
666     {
667       _block = soc4210;
668       _nr_blocks = sizeof(soc4210) / sizeof(soc4210[0]);
669     }
670
671   calc_nr_irq();
672 }
673
674 /**
675  * \pre must run on the CPU given in \a cpu.
676  */
677 PUBLIC
678 void
679 Mgr_ext::set_cpu(Mword irqnum, Cpu_number cpu) const
680 {
681   if (!Platform::is_4412() && irqnum == 80)  // MCT_L1
682     _gic.cpu(cpu)->set_cpu(80, cpu);
683   else
684     WARNX(Warning, "IRQ%ld: ignoring CPU setting (%d).\n", irqnum,
685           cxx::int_value<Cpu_number>(cpu));
686 }
687
688 IMPLEMENT static FIASCO_INIT
689 void Pic::init()
690 {
691   Mgr_ext *m = new Boot_object<Mgr_ext>();
692   Irq_mgr::mgr = m;
693   gic = &m->_gic;
694 }
695
696 PUBLIC static
697 void
698 Pic::reinit(Cpu_number cpu)
699 {
700   gic.cpu(cpu)->init(true, 96);
701 }
702
703 class Check_irq0 : public Irq_base
704 {
705 public:
706   Check_irq0() { set_hit(&hndl); }
707   static void hndl(Irq_base *, Upstream_irq const *)
708   {
709     printf("IRQ0 appeared on CPU%d\n",
710            cxx::int_value<Cpu_number>(current_cpu()));
711   }
712 private:
713   void switch_mode(unsigned) {}
714 };
715
716 DEFINE_PER_CPU static Per_cpu<Static_object<Check_irq0> > _check_irq0;
717
718
719 PUBLIC static
720 void Pic::init_ap(Cpu_number cpu)
721 {
722   if (Platform::is_4412())
723     {
724       assert(cpu > Cpu_number(0));
725       assert(cpu < Cpu_number(4));
726
727       unsigned phys_cpu = cxx::int_value<Cpu_phys_id>(Cpu::cpus.cpu(cpu).phys_id());
728       gic.cpu(cpu).construct(
729           Kmem::mmio_remap(Mem_layout::Gic_cpu_ext_cpu0_phys_base + phys_cpu * 0x4000),
730           Kmem::mmio_remap(Mem_layout::Gic_dist_ext_cpu0_phys_base + phys_cpu * 0x4000),
731           gic.cpu(Cpu_number(0)));
732     }
733   else
734     {
735       assert (cpu == Cpu_number(1));
736       assert (Cpu::cpus.cpu(cpu).phys_id() == Cpu_phys_id(1));
737
738       gic.cpu(cpu).construct(Kmem::mmio_remap(Mem_layout::Gic_cpu_ext_cpu1_phys_base),
739                              Kmem::mmio_remap(Mem_layout::Gic_dist_ext_cpu1_phys_base),
740                              gic.cpu(Cpu_number(0)));
741     }
742
743   gic.cpu(cpu)->init_ap();
744
745
746   // This is a debug facility as we've been seeing IRQ0
747   // happening under (non-usual) high load
748   _check_irq0.cpu(cpu).construct();
749   gic.cpu(cpu)->alloc(_check_irq0.cpu(cpu), 0);
750 }
751
752
753 extern "C"
754 void irq_handler()
755 { nonull_static_cast<Mgr_ext *>(Irq_mgr::mgr)->_gic.current()->hit(0); }
756
757 //-------------------------------------------------------------------
758 IMPLEMENTATION [arm && exynos_extgic && arm_em_tz]:
759
760 PUBLIC static
761 void
762 Pic::set_pending_irq(unsigned group32num, Unsigned32 val)
763 {
764   gic.current()->set_pending_irq(group32num, val);
765 }
766
767 // ------------------------------------------------------------------------
768 IMPLEMENTATION [exynos5]:
769
770 #include "platform.h"
771
772 EXTENSION class Pic
773 {
774 };
775
776 class Mgr : public Mgr_exynos
777 {
778   Irq chip(Mword irqnum) const
779   {
780     Mword origirq = irqnum;
781
782     for (unsigned i = 0; i < _nr_blocks; ++i)
783       {
784         if (irqnum < _block[i].sz)
785           return Irq(_block[i].chip, irqnum);
786
787         irqnum -= _block[i].sz;
788       }
789
790     printf("KERNEL: exynos-irq: Invalid irqnum=%ld\n", origirq);
791     return Irq();
792   }
793
794 private:
795   friend class Pic;
796   Combiner_chip *_cc;
797   Gpio_wakeup_chip *_wu_gc;
798   Gpio_eint_chip *_ei_gc1, *_ei_gc2;
799   Gpio_eint_chip *_ei_gc3, *_ei_gc4;
800 };
801
802 PUBLIC
803 Mgr::Mgr()
804 {
805   Gic *g = Pic::gic.construct(Kmem::mmio_remap(Mem_layout::Gic_cpu_phys_base),
806                               Kmem::mmio_remap(Mem_layout::Gic_dist_phys_base));
807
808   _cc = new Boot_object<Combiner_chip>();
809
810   _wu_gc = new Boot_object<Gpio_wakeup_chip>(Kmem::Gpio1_phys_base);
811
812   _ei_gc1 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio1_phys_base), 13 * 8);
813   _ei_gc2 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio2_phys_base),  8 * 8);
814   _ei_gc3 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio3_phys_base),  5 * 8);
815   _ei_gc4 = new Boot_object<Gpio_eint_chip>(Kmem::mmio_remap(Mem_layout::Gpio4_phys_base),  1 * 8);
816
817   // Combiners
818   for (unsigned i = 0; i < 32; ++i)
819     {
820       g->alloc(new Boot_object<Combiner_cascade_irq>(i, _cc), i + 32);
821       g->unmask(i + 32);
822     }
823
824   _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 0), 8 * 23 + 0);
825   _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, 1), 8 * 24 + 0);
826   for (int i = 25, nr = 2; i < 32; ++i, nr += 2)
827     {
828       _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, nr + 0), 8 * i + 0);
829       _cc->alloc(new Boot_object<Gpio_cascade_wu01_irq>(_wu_gc, nr + 1), 8 * i + 1);
830     }
831
832   // GPIO-wakeup16-31: GIC:32+32
833   g->alloc(new Boot_object<Gpio_cascade_wu23_irq>(_wu_gc), 64);
834   g->unmask(64);
835
836   if (0)
837     {
838       // xa GIC:32+47
839       g->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc1), 79);
840       g->unmask(79);
841
842       // xb GIC:32+46
843       g->alloc(new Boot_object<Gpio_cascade_xab_irq>(_ei_gc2), 78);
844       g->unmask(78);
845     }
846
847   // 5250
848   //  - part1: ext-int 0x700: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 30
849   //                   0xe00: 40, 41, 42, 43
850   //  - part2: ext-int 0x700: 14, 15, 16, 17, 18, 19, 20, 21, 22
851   //  - part3: ext-int 0x700: 60, 61, 62, 63, 64
852   //  - part4: ext-int 0x700: 50
853
854   static Chip_block socblock[] = {
855     { 160,                Pic::gic },
856     { 32 * 8,             _cc },
857     { 32,                 _wu_gc },
858     { _ei_gc1->nr_irqs(), _ei_gc1 },
859     { _ei_gc2->nr_irqs(), _ei_gc2 },
860     { _ei_gc3->nr_irqs(), _ei_gc3 },
861     { _ei_gc4->nr_irqs(), _ei_gc4 },
862   };
863
864   _block = socblock;
865   _nr_blocks = sizeof(socblock) / sizeof(socblock[0]);
866
867   calc_nr_irq();
868 }
869
870 /**
871  * \pre must run on the CPU given in \a cpu.
872  */
873 PUBLIC
874 void
875 Mgr::set_cpu(Mword irqnum, Cpu_number cpu) const
876 {
877   // this handles only the MCT_L[01] timers
878   if (   irqnum == 152   // MCT_L0
879       || irqnum == 153)  // MCT_L1
880     Pic::gic->set_cpu(irqnum, cpu);
881   else
882     WARNX(Warning, "IRQ%ld: ignoring CPU setting (%d).\n",
883           irqnum, cxx::int_value<Cpu_number>(cpu));
884 }
885
886 IMPLEMENT static FIASCO_INIT
887 void Pic::init()
888 {
889   Irq_mgr::mgr = new Boot_object<Mgr>();
890 }
891
892 PUBLIC static
893 void
894 Pic::reinit(Cpu_number)
895 {
896   gic->init(true);
897 }
898
899 PUBLIC static
900 void Pic::init_ap(Cpu_number)
901 {
902   gic->init_ap();
903 }
904
905 //---------------------------------------------------------------------------
906 IMPLEMENTATION [debug && exynos]:
907
908 PUBLIC
909 char const *
910 Combiner_chip::chip_type() const
911 { return "Comb"; }
912
913 PUBLIC
914 char const *
915 Gpio_eint_chip::chip_type() const
916 { return "EI-Gpio"; }
917
918 PUBLIC
919 char const *
920 Gpio_wakeup_chip::chip_type() const
921 { return "WU-GPIO"; }