|
1 /* |
|
2 * Intel XScale PXA Programmable Interrupt Controller. |
|
3 * |
|
4 * Copyright (c) 2006 Openedhand Ltd. |
|
5 * Copyright (c) 2006 Thorsten Zitterell |
|
6 * Written by Andrzej Zaborowski <balrog@zabor.org> |
|
7 * |
|
8 * This code is licenced under the GPL. |
|
9 */ |
|
10 |
|
11 #include "hw.h" |
|
12 #include "pxa.h" |
|
13 |
|
14 #define ICIP 0x00 /* Interrupt Controller IRQ Pending register */ |
|
15 #define ICMR 0x04 /* Interrupt Controller Mask register */ |
|
16 #define ICLR 0x08 /* Interrupt Controller Level register */ |
|
17 #define ICFP 0x0c /* Interrupt Controller FIQ Pending register */ |
|
18 #define ICPR 0x10 /* Interrupt Controller Pending register */ |
|
19 #define ICCR 0x14 /* Interrupt Controller Control register */ |
|
20 #define ICHP 0x18 /* Interrupt Controller Highest Priority register */ |
|
21 #define IPR0 0x1c /* Interrupt Controller Priority register 0 */ |
|
22 #define IPR31 0x98 /* Interrupt Controller Priority register 31 */ |
|
23 #define ICIP2 0x9c /* Interrupt Controller IRQ Pending register 2 */ |
|
24 #define ICMR2 0xa0 /* Interrupt Controller Mask register 2 */ |
|
25 #define ICLR2 0xa4 /* Interrupt Controller Level register 2 */ |
|
26 #define ICFP2 0xa8 /* Interrupt Controller FIQ Pending register 2 */ |
|
27 #define ICPR2 0xac /* Interrupt Controller Pending register 2 */ |
|
28 #define IPR32 0xb0 /* Interrupt Controller Priority register 32 */ |
|
29 #define IPR39 0xcc /* Interrupt Controller Priority register 39 */ |
|
30 |
|
31 #define PXA2XX_PIC_SRCS 40 |
|
32 |
|
33 struct pxa2xx_pic_state_s { |
|
34 CPUState *cpu_env; |
|
35 uint32_t int_enabled[2]; |
|
36 uint32_t int_pending[2]; |
|
37 uint32_t is_fiq[2]; |
|
38 uint32_t int_idle; |
|
39 uint32_t priority[PXA2XX_PIC_SRCS]; |
|
40 }; |
|
41 |
|
42 static void pxa2xx_pic_update(void *opaque) |
|
43 { |
|
44 uint32_t mask[2]; |
|
45 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
46 |
|
47 if (s->cpu_env->halted) { |
|
48 mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle); |
|
49 mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle); |
|
50 if (mask[0] || mask[1]) |
|
51 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB); |
|
52 } |
|
53 |
|
54 mask[0] = s->int_pending[0] & s->int_enabled[0]; |
|
55 mask[1] = s->int_pending[1] & s->int_enabled[1]; |
|
56 |
|
57 if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1])) |
|
58 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); |
|
59 else |
|
60 cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); |
|
61 |
|
62 if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1])) |
|
63 cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); |
|
64 else |
|
65 cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); |
|
66 } |
|
67 |
|
68 /* Note: Here level means state of the signal on a pin, not |
|
69 * IRQ/FIQ distinction as in PXA Developer Manual. */ |
|
70 static void pxa2xx_pic_set_irq(void *opaque, int irq, int level) |
|
71 { |
|
72 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
73 int int_set = (irq >= 32); |
|
74 irq &= 31; |
|
75 |
|
76 if (level) |
|
77 s->int_pending[int_set] |= 1 << irq; |
|
78 else |
|
79 s->int_pending[int_set] &= ~(1 << irq); |
|
80 |
|
81 pxa2xx_pic_update(opaque); |
|
82 } |
|
83 |
|
84 static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) { |
|
85 int i, int_set, irq; |
|
86 uint32_t bit, mask[2]; |
|
87 uint32_t ichp = 0x003f003f; /* Both IDs invalid */ |
|
88 |
|
89 mask[0] = s->int_pending[0] & s->int_enabled[0]; |
|
90 mask[1] = s->int_pending[1] & s->int_enabled[1]; |
|
91 |
|
92 for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) { |
|
93 irq = s->priority[i] & 0x3f; |
|
94 if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) { |
|
95 /* Source peripheral ID is valid. */ |
|
96 bit = 1 << (irq & 31); |
|
97 int_set = (irq >= 32); |
|
98 |
|
99 if (mask[int_set] & bit & s->is_fiq[int_set]) { |
|
100 /* FIQ asserted */ |
|
101 ichp &= 0xffff0000; |
|
102 ichp |= (1 << 15) | irq; |
|
103 } |
|
104 |
|
105 if (mask[int_set] & bit & ~s->is_fiq[int_set]) { |
|
106 /* IRQ asserted */ |
|
107 ichp &= 0x0000ffff; |
|
108 ichp |= (1 << 31) | (irq << 16); |
|
109 } |
|
110 } |
|
111 } |
|
112 |
|
113 return ichp; |
|
114 } |
|
115 |
|
116 static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset) |
|
117 { |
|
118 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
119 |
|
120 switch (offset) { |
|
121 case ICIP: /* IRQ Pending register */ |
|
122 return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0]; |
|
123 case ICIP2: /* IRQ Pending register 2 */ |
|
124 return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1]; |
|
125 case ICMR: /* Mask register */ |
|
126 return s->int_enabled[0]; |
|
127 case ICMR2: /* Mask register 2 */ |
|
128 return s->int_enabled[1]; |
|
129 case ICLR: /* Level register */ |
|
130 return s->is_fiq[0]; |
|
131 case ICLR2: /* Level register 2 */ |
|
132 return s->is_fiq[1]; |
|
133 case ICCR: /* Idle mask */ |
|
134 return (s->int_idle == 0); |
|
135 case ICFP: /* FIQ Pending register */ |
|
136 return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0]; |
|
137 case ICFP2: /* FIQ Pending register 2 */ |
|
138 return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1]; |
|
139 case ICPR: /* Pending register */ |
|
140 return s->int_pending[0]; |
|
141 case ICPR2: /* Pending register 2 */ |
|
142 return s->int_pending[1]; |
|
143 case IPR0 ... IPR31: |
|
144 return s->priority[0 + ((offset - IPR0 ) >> 2)]; |
|
145 case IPR32 ... IPR39: |
|
146 return s->priority[32 + ((offset - IPR32) >> 2)]; |
|
147 case ICHP: /* Highest Priority register */ |
|
148 return pxa2xx_pic_highest(s); |
|
149 default: |
|
150 printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); |
|
151 return 0; |
|
152 } |
|
153 } |
|
154 |
|
155 static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset, |
|
156 uint32_t value) |
|
157 { |
|
158 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
159 |
|
160 switch (offset) { |
|
161 case ICMR: /* Mask register */ |
|
162 s->int_enabled[0] = value; |
|
163 break; |
|
164 case ICMR2: /* Mask register 2 */ |
|
165 s->int_enabled[1] = value; |
|
166 break; |
|
167 case ICLR: /* Level register */ |
|
168 s->is_fiq[0] = value; |
|
169 break; |
|
170 case ICLR2: /* Level register 2 */ |
|
171 s->is_fiq[1] = value; |
|
172 break; |
|
173 case ICCR: /* Idle mask */ |
|
174 s->int_idle = (value & 1) ? 0 : ~0; |
|
175 break; |
|
176 case IPR0 ... IPR31: |
|
177 s->priority[0 + ((offset - IPR0 ) >> 2)] = value & 0x8000003f; |
|
178 break; |
|
179 case IPR32 ... IPR39: |
|
180 s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f; |
|
181 break; |
|
182 default: |
|
183 printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset); |
|
184 return; |
|
185 } |
|
186 pxa2xx_pic_update(opaque); |
|
187 } |
|
188 |
|
189 /* Interrupt Controller Coprocessor Space Register Mapping */ |
|
190 static const int pxa2xx_cp_reg_map[0x10] = { |
|
191 [0x0 ... 0xf] = -1, |
|
192 [0x0] = ICIP, |
|
193 [0x1] = ICMR, |
|
194 [0x2] = ICLR, |
|
195 [0x3] = ICFP, |
|
196 [0x4] = ICPR, |
|
197 [0x5] = ICHP, |
|
198 [0x6] = ICIP2, |
|
199 [0x7] = ICMR2, |
|
200 [0x8] = ICLR2, |
|
201 [0x9] = ICFP2, |
|
202 [0xa] = ICPR2, |
|
203 }; |
|
204 |
|
205 static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm) |
|
206 { |
|
207 target_phys_addr_t offset; |
|
208 |
|
209 if (pxa2xx_cp_reg_map[reg] == -1) { |
|
210 printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
211 return 0; |
|
212 } |
|
213 |
|
214 offset = pxa2xx_cp_reg_map[reg]; |
|
215 return pxa2xx_pic_mem_read(opaque, offset); |
|
216 } |
|
217 |
|
218 static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm, |
|
219 uint32_t value) |
|
220 { |
|
221 target_phys_addr_t offset; |
|
222 |
|
223 if (pxa2xx_cp_reg_map[reg] == -1) { |
|
224 printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
225 return; |
|
226 } |
|
227 |
|
228 offset = pxa2xx_cp_reg_map[reg]; |
|
229 pxa2xx_pic_mem_write(opaque, offset, value); |
|
230 } |
|
231 |
|
232 static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = { |
|
233 pxa2xx_pic_mem_read, |
|
234 pxa2xx_pic_mem_read, |
|
235 pxa2xx_pic_mem_read, |
|
236 }; |
|
237 |
|
238 static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = { |
|
239 pxa2xx_pic_mem_write, |
|
240 pxa2xx_pic_mem_write, |
|
241 pxa2xx_pic_mem_write, |
|
242 }; |
|
243 |
|
244 static void pxa2xx_pic_save(QEMUFile *f, void *opaque) |
|
245 { |
|
246 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
247 int i; |
|
248 |
|
249 for (i = 0; i < 2; i ++) |
|
250 qemu_put_be32s(f, &s->int_enabled[i]); |
|
251 for (i = 0; i < 2; i ++) |
|
252 qemu_put_be32s(f, &s->int_pending[i]); |
|
253 for (i = 0; i < 2; i ++) |
|
254 qemu_put_be32s(f, &s->is_fiq[i]); |
|
255 qemu_put_be32s(f, &s->int_idle); |
|
256 for (i = 0; i < PXA2XX_PIC_SRCS; i ++) |
|
257 qemu_put_be32s(f, &s->priority[i]); |
|
258 } |
|
259 |
|
260 static int pxa2xx_pic_load(QEMUFile *f, void *opaque, int version_id) |
|
261 { |
|
262 struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque; |
|
263 int i; |
|
264 |
|
265 for (i = 0; i < 2; i ++) |
|
266 qemu_get_be32s(f, &s->int_enabled[i]); |
|
267 for (i = 0; i < 2; i ++) |
|
268 qemu_get_be32s(f, &s->int_pending[i]); |
|
269 for (i = 0; i < 2; i ++) |
|
270 qemu_get_be32s(f, &s->is_fiq[i]); |
|
271 qemu_get_be32s(f, &s->int_idle); |
|
272 for (i = 0; i < PXA2XX_PIC_SRCS; i ++) |
|
273 qemu_get_be32s(f, &s->priority[i]); |
|
274 |
|
275 pxa2xx_pic_update(opaque); |
|
276 return 0; |
|
277 } |
|
278 |
|
279 qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env) |
|
280 { |
|
281 struct pxa2xx_pic_state_s *s; |
|
282 int iomemtype; |
|
283 qemu_irq *qi; |
|
284 |
|
285 s = (struct pxa2xx_pic_state_s *) |
|
286 qemu_mallocz(sizeof(struct pxa2xx_pic_state_s)); |
|
287 if (!s) |
|
288 return NULL; |
|
289 |
|
290 s->cpu_env = env; |
|
291 |
|
292 s->int_pending[0] = 0; |
|
293 s->int_pending[1] = 0; |
|
294 s->int_enabled[0] = 0; |
|
295 s->int_enabled[1] = 0; |
|
296 s->is_fiq[0] = 0; |
|
297 s->is_fiq[1] = 0; |
|
298 |
|
299 qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS); |
|
300 |
|
301 /* Enable IC memory-mapped registers access. */ |
|
302 iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn, |
|
303 pxa2xx_pic_writefn, s); |
|
304 cpu_register_physical_memory(base, 0x00100000, iomemtype); |
|
305 |
|
306 /* Enable IC coprocessor access. */ |
|
307 cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s); |
|
308 |
|
309 register_savevm("pxa2xx_pic", 0, 0, pxa2xx_pic_save, pxa2xx_pic_load, s); |
|
310 |
|
311 return qi; |
|
312 } |