]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/irq.c
bcm: make sure fiq is on enabled on cpu0
[plan9front.git] / sys / src / 9 / bcm / irq.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8 #include "../port/error.h"
9
10 #define INTREGS         (VIRTIO+0xB200)
11
12 enum {
13         Fiqenable = 1<<7,
14
15         Localtimerint   = 0x40,
16         Localmboxint    = 0x50,
17         Localintpending = 0x60,
18 };
19
20 /*
21  * interrupt control registers
22  */
23 typedef struct Intregs Intregs;
24 struct Intregs {
25         u32int  ARMpending;
26         u32int  GPUpending[2];
27         u32int  FIQctl;
28         u32int  GPUenable[2];
29         u32int  ARMenable;
30         u32int  GPUdisable[2];
31         u32int  ARMdisable;
32 };
33
34 typedef struct Vctl Vctl;
35 struct Vctl {
36         Vctl    *next;
37         int     irq;
38         u32int  *reg;
39         u32int  mask;
40         void    (*f)(Ureg*, void*);
41         void    *a;
42 };
43
44 static Lock vctllock;
45 static Vctl *vctl[MAXMACH], *vfiq;
46
47 void
48 intrcpushutdown(void)
49 {
50         u32int *enable;
51
52         if(soc.armlocal == 0)
53                 return;
54         enable = (u32int*)(ARMLOCAL + Localtimerint) + m->machno;
55         *enable = 0;
56         if(m->machno){
57                 enable = (u32int*)(ARMLOCAL + Localmboxint) + m->machno;
58                 *enable = 1;
59         }
60 }
61
62 void
63 intrsoff(void)
64 {
65         Intregs *ip;
66         int disable;
67
68         ip = (Intregs*)INTREGS;
69         disable = ~0;
70         ip->GPUdisable[0] = disable;
71         ip->GPUdisable[1] = disable;
72         ip->ARMdisable = disable;
73         ip->FIQctl = 0;
74 }
75
76 /*
77  *  called by trap to handle irq interrupts.
78  *  returns true iff a clock interrupt, thus maybe reschedule.
79  */
80 int
81 irq(Ureg* ureg)
82 {
83         Vctl *v;
84         int clockintr;
85
86         m->intr++;
87         clockintr = 0;
88         for(v = vctl[m->machno]; v != nil; v = v->next)
89                 if((*v->reg & v->mask) != 0){
90                         coherence();
91                         v->f(ureg, v->a);
92                         coherence();
93                         if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
94                                 clockintr = 1;
95                 }
96         return clockintr;
97 }
98
99 /*
100  * called direct from lexception.s to handle fiq interrupt.
101  */
102 void
103 fiq(Ureg *ureg)
104 {
105         Vctl *v;
106
107         m->intr++;
108         v = vfiq;
109         if(v == nil || m->machno)
110                 panic("cpu%d: unexpected item in bagging area", m->machno);
111         coherence();
112         v->f(ureg, v->a);
113         coherence();
114 }
115
116 void
117 irqenable(int irq, void (*f)(Ureg*, void*), void* a)
118 {
119         Vctl *v;
120         Intregs *ip;
121         u32int *enable;
122         int cpu;
123
124         ip = (Intregs*)INTREGS;
125         if((v = xalloc(sizeof(Vctl))) == nil)
126                 panic("irqenable: no mem");
127         cpu = 0;
128         v->irq = irq;
129         if(irq >= IRQlocal){
130                 cpu = m->machno;
131                 v->reg = (u32int*)(ARMLOCAL + Localintpending) + cpu;
132                 if(irq >= IRQmbox0)
133                         enable = (u32int*)(ARMLOCAL + Localmboxint) + cpu;
134                 else
135                         enable = (u32int*)(ARMLOCAL + Localtimerint) + cpu;
136                 v->mask = 1 << (irq - IRQlocal);
137         }else if(irq >= IRQbasic){
138                 enable = &ip->ARMenable;
139                 v->reg = &ip->ARMpending;
140                 v->mask = 1 << (irq - IRQbasic);
141         }else{
142                 enable = &ip->GPUenable[irq/32];
143                 v->reg = &ip->GPUpending[irq/32];
144                 v->mask = 1 << (irq % 32);
145         }
146         v->f = f;
147         v->a = a;
148         lock(&vctllock);
149         if(irq == IRQfiq){
150                 assert((ip->FIQctl & Fiqenable) == 0);
151                 assert((*enable & v->mask) == 0);
152                 assert(cpu == 0);
153                 vfiq = v;
154                 ip->FIQctl = Fiqenable | irq;
155         }else{
156                 v->next = vctl[cpu];
157                 vctl[cpu] = v;
158                 if(irq >= IRQmbox0){
159                         if(irq <= IRQmbox3)
160                                 *enable |= 1 << (irq - IRQmbox0);
161                 }else if(irq >= IRQlocal)
162                         *enable |= 1 << (irq - IRQlocal);
163                 else
164                         *enable = v->mask;
165         }
166         unlock(&vctllock);
167 }