Revision 106627d0 hw/omap.c
b/hw/omap.c | ||
---|---|---|
80 | 80 |
} |
81 | 81 |
|
82 | 82 |
/* Interrupt Handlers */ |
83 |
struct omap_intr_handler_s { |
|
84 |
qemu_irq *pins; |
|
85 |
qemu_irq *parent_pic; |
|
86 |
target_phys_addr_t base; |
|
87 |
|
|
88 |
/* state */ |
|
83 |
struct omap_intr_handler_bank_s { |
|
89 | 84 |
uint32_t irqs; |
85 |
uint32_t inputs; |
|
90 | 86 |
uint32_t mask; |
91 |
uint32_t sens_edge; |
|
92 | 87 |
uint32_t fiq; |
93 |
int priority[32]; |
|
94 |
uint32_t new_irq_agr; |
|
95 |
uint32_t new_fiq_agr; |
|
96 |
int sir_irq; |
|
97 |
int sir_fiq; |
|
98 |
int stats[32]; |
|
88 |
uint32_t sens_edge; |
|
89 |
unsigned char priority[32]; |
|
99 | 90 |
}; |
100 | 91 |
|
101 |
static void omap_inth_update(struct omap_intr_handler_s *s) |
|
102 |
{ |
|
103 |
uint32_t irq = s->irqs & ~s->mask & ~s->fiq; |
|
104 |
uint32_t fiq = s->irqs & ~s->mask & s->fiq; |
|
92 |
struct omap_intr_handler_s { |
|
93 |
qemu_irq *pins; |
|
94 |
qemu_irq parent_intr[2]; |
|
95 |
target_phys_addr_t base; |
|
96 |
unsigned char nbanks; |
|
105 | 97 |
|
106 |
if (s->new_irq_agr || !irq) {
|
|
107 |
qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq);
|
|
108 |
if (irq)
|
|
109 |
s->new_irq_agr = 0;
|
|
110 |
}
|
|
98 |
/* state */
|
|
99 |
uint32_t new_agr[2];
|
|
100 |
int sir_intr[2];
|
|
101 |
struct omap_intr_handler_bank_s banks[];
|
|
102 |
};
|
|
111 | 103 |
|
112 |
if (s->new_fiq_agr || !irq) { |
|
113 |
qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq); |
|
114 |
if (fiq) |
|
115 |
s->new_fiq_agr = 0; |
|
104 |
static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) |
|
105 |
{ |
|
106 |
int i, j, sir_intr, p_intr, p, f; |
|
107 |
uint32_t level; |
|
108 |
sir_intr = 0; |
|
109 |
p_intr = 255; |
|
110 |
|
|
111 |
/* Find the interrupt line with the highest dynamic priority. |
|
112 |
* Note: 0 denotes the hightest priority. |
|
113 |
* If all interrupts have the same priority, the default order is IRQ_N, |
|
114 |
* IRQ_N-1,...,IRQ_0. */ |
|
115 |
for (j = 0; j < s->nbanks; ++j) { |
|
116 |
level = s->banks[j].irqs & ~s->banks[j].mask & |
|
117 |
(is_fiq ? s->banks[j].fiq : ~s->banks[j].fiq); |
|
118 |
for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, |
|
119 |
level >>= f) { |
|
120 |
p = s->banks[j].priority[i]; |
|
121 |
if (p <= p_intr) { |
|
122 |
p_intr = p; |
|
123 |
sir_intr = 32 * j + i; |
|
124 |
} |
|
125 |
f = ffs(level >> 1); |
|
126 |
} |
|
116 | 127 |
} |
128 |
s->sir_intr[is_fiq] = sir_intr; |
|
117 | 129 |
} |
118 | 130 |
|
119 |
static void omap_inth_sir_update(struct omap_intr_handler_s *s)
|
|
131 |
static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq)
|
|
120 | 132 |
{ |
121 |
int i, intr_irq, intr_fiq, p_irq, p_fiq, p, f;
|
|
122 |
uint32_t level = s->irqs & ~s->mask;
|
|
133 |
int i; |
|
134 |
uint32_t has_intr = 0;
|
|
123 | 135 |
|
124 |
intr_irq = 0; |
|
125 |
intr_fiq = 0; |
|
126 |
p_irq = -1; |
|
127 |
p_fiq = -1; |
|
128 |
/* Find the interrupt line with the highest dynamic priority */ |
|
129 |
for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, level >>= f) { |
|
130 |
p = s->priority[i]; |
|
131 |
if (s->fiq & (1 << i)) { |
|
132 |
if (p > p_fiq) { |
|
133 |
p_fiq = p; |
|
134 |
intr_fiq = i; |
|
135 |
} |
|
136 |
} else { |
|
137 |
if (p > p_irq) { |
|
138 |
p_irq = p; |
|
139 |
intr_irq = i; |
|
140 |
} |
|
141 |
} |
|
136 |
for (i = 0; i < s->nbanks; ++i) |
|
137 |
has_intr |= s->banks[i].irqs & ~s->banks[i].mask & |
|
138 |
(is_fiq ? s->banks[i].fiq : ~s->banks[i].fiq); |
|
142 | 139 |
|
143 |
f = ffs(level >> 1); |
|
140 |
if (s->new_agr[is_fiq] && has_intr) { |
|
141 |
s->new_agr[is_fiq] = 0; |
|
142 |
omap_inth_sir_update(s, is_fiq); |
|
143 |
qemu_set_irq(s->parent_intr[is_fiq], 1); |
|
144 | 144 |
} |
145 |
|
|
146 |
s->sir_irq = intr_irq; |
|
147 |
s->sir_fiq = intr_fiq; |
|
148 | 145 |
} |
149 | 146 |
|
150 | 147 |
#define INT_FALLING_EDGE 0 |
... | ... | |
155 | 152 |
struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; |
156 | 153 |
uint32_t rise; |
157 | 154 |
|
155 |
struct omap_intr_handler_bank_s *bank = &ih->banks[irq >> 5]; |
|
156 |
int n = irq & 31; |
|
157 |
|
|
158 | 158 |
if (req) { |
159 |
rise = ~ih->irqs & (1 << irq); |
|
160 |
ih->irqs |= rise; |
|
161 |
ih->stats[irq] += !!rise; |
|
159 |
rise = ~bank->irqs & (1 << n); |
|
160 |
if (~bank->sens_edge & (1 << n)) |
|
161 |
rise &= ~bank->inputs & (1 << n); |
|
162 |
|
|
163 |
bank->inputs |= (1 << n); |
|
164 |
if (rise) { |
|
165 |
bank->irqs |= rise; |
|
166 |
omap_inth_update(ih, 0); |
|
167 |
omap_inth_update(ih, 1); |
|
168 |
} |
|
162 | 169 |
} else { |
163 |
rise = ih->sens_edge & ih->irqs & (1 << irq); |
|
164 |
ih->irqs &= ~rise; |
|
165 |
} |
|
166 |
|
|
167 |
if (rise & ~ih->mask) { |
|
168 |
omap_inth_sir_update(ih); |
|
169 |
|
|
170 |
omap_inth_update(ih); |
|
170 |
rise = bank->sens_edge & bank->irqs & (1 << n); |
|
171 |
bank->irqs &= ~rise; |
|
172 |
bank->inputs &= ~(1 << n); |
|
171 | 173 |
} |
172 | 174 |
} |
173 | 175 |
|
... | ... | |
175 | 177 |
{ |
176 | 178 |
struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; |
177 | 179 |
int i, offset = addr - s->base; |
180 |
int bank_no = offset >> 8; |
|
181 |
int line_no; |
|
182 |
struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; |
|
183 |
offset &= 0xff; |
|
178 | 184 |
|
179 | 185 |
switch (offset) { |
180 | 186 |
case 0x00: /* ITR */ |
181 |
return s->irqs;
|
|
187 |
return bank->irqs;
|
|
182 | 188 |
|
183 | 189 |
case 0x04: /* MIR */ |
184 |
return s->mask;
|
|
190 |
return bank->mask;
|
|
185 | 191 |
|
186 | 192 |
case 0x10: /* SIR_IRQ_CODE */ |
187 |
i = s->sir_irq; |
|
188 |
if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { |
|
189 |
s->irqs &= ~(1 << i); |
|
190 |
omap_inth_sir_update(s); |
|
191 |
omap_inth_update(s); |
|
192 |
} |
|
193 |
return i; |
|
194 |
|
|
195 |
case 0x14: /* SIR_FIQ_CODE */ |
|
196 |
i = s->sir_fiq; |
|
197 |
if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) { |
|
198 |
s->irqs &= ~(1 << i); |
|
199 |
omap_inth_sir_update(s); |
|
200 |
omap_inth_update(s); |
|
201 |
} |
|
193 |
case 0x14: /* SIR_FIQ_CODE */ |
|
194 |
if (bank_no != 0) |
|
195 |
break; |
|
196 |
line_no = s->sir_intr[(offset - 0x10) >> 2]; |
|
197 |
bank = &s->banks[line_no >> 5]; |
|
198 |
i = line_no & 31; |
|
199 |
if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE) |
|
200 |
bank->irqs &= ~(1 << i); |
|
202 | 201 |
return i; |
203 | 202 |
|
204 | 203 |
case 0x18: /* CONTROL_REG */ |
204 |
if (bank_no != 0) |
|
205 |
break; |
|
205 | 206 |
return 0; |
206 | 207 |
|
207 | 208 |
case 0x1c: /* ILR0 */ |
... | ... | |
237 | 238 |
case 0x94: /* ILR30 */ |
238 | 239 |
case 0x98: /* ILR31 */ |
239 | 240 |
i = (offset - 0x1c) >> 2; |
240 |
return (s->priority[i] << 2) |
|
|
241 |
(((s->sens_edge >> i) & 1) << 1) |
|
|
242 |
((s->fiq >> i) & 1);
|
|
241 |
return (bank->priority[i] << 2) |
|
|
242 |
(((bank->sens_edge >> i) & 1) << 1) |
|
|
243 |
((bank->fiq >> i) & 1);
|
|
243 | 244 |
|
244 | 245 |
case 0x9c: /* ISR */ |
245 | 246 |
return 0x00000000; |
246 | 247 |
|
247 |
default: |
|
248 |
OMAP_BAD_REG(addr); |
|
249 |
break; |
|
250 | 248 |
} |
249 |
OMAP_BAD_REG(addr); |
|
251 | 250 |
return 0; |
252 | 251 |
} |
253 | 252 |
|
... | ... | |
256 | 255 |
{ |
257 | 256 |
struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; |
258 | 257 |
int i, offset = addr - s->base; |
258 |
int bank_no = offset >> 8; |
|
259 |
struct omap_intr_handler_bank_s *bank = &s->banks[bank_no]; |
|
260 |
offset &= 0xff; |
|
259 | 261 |
|
260 | 262 |
switch (offset) { |
261 | 263 |
case 0x00: /* ITR */ |
262 |
s->irqs &= value | 1;
|
|
263 |
omap_inth_sir_update(s);
|
|
264 |
omap_inth_update(s);
|
|
264 |
/* Important: ignore the clearing if the IRQ is level-triggered and
|
|
265 |
the input bit is 1 */
|
|
266 |
bank->irqs &= value | (bank->inputs & bank->sens_edge);
|
|
265 | 267 |
return; |
266 | 268 |
|
267 | 269 |
case 0x04: /* MIR */ |
268 |
s->mask = value;
|
|
269 |
omap_inth_sir_update(s);
|
|
270 |
omap_inth_update(s); |
|
270 |
bank->mask = value;
|
|
271 |
omap_inth_update(s, 0);
|
|
272 |
omap_inth_update(s, 1);
|
|
271 | 273 |
return; |
272 | 274 |
|
273 | 275 |
case 0x10: /* SIR_IRQ_CODE */ |
... | ... | |
276 | 278 |
break; |
277 | 279 |
|
278 | 280 |
case 0x18: /* CONTROL_REG */ |
279 |
if (value & 2) |
|
280 |
s->new_fiq_agr = ~0; |
|
281 |
if (value & 1) |
|
282 |
s->new_irq_agr = ~0; |
|
283 |
omap_inth_update(s); |
|
281 |
if (bank_no != 0) |
|
282 |
break; |
|
283 |
if (value & 2) { |
|
284 |
qemu_set_irq(s->parent_intr[1], 0); |
|
285 |
s->new_agr[1] = ~0; |
|
286 |
omap_inth_update(s, 1); |
|
287 |
} |
|
288 |
if (value & 1) { |
|
289 |
qemu_set_irq(s->parent_intr[0], 0); |
|
290 |
s->new_agr[0] = ~0; |
|
291 |
omap_inth_update(s, 0); |
|
292 |
} |
|
284 | 293 |
return; |
285 | 294 |
|
286 | 295 |
case 0x1c: /* ILR0 */ |
... | ... | |
316 | 325 |
case 0x94: /* ILR30 */ |
317 | 326 |
case 0x98: /* ILR31 */ |
318 | 327 |
i = (offset - 0x1c) >> 2; |
319 |
s->priority[i] = (value >> 2) & 0x1f;
|
|
320 |
s->sens_edge &= ~(1 << i);
|
|
321 |
s->sens_edge |= ((value >> 1) & 1) << i;
|
|
322 |
s->fiq &= ~(1 << i);
|
|
323 |
s->fiq |= (value & 1) << i;
|
|
328 |
bank->priority[i] = (value >> 2) & 0x1f;
|
|
329 |
bank->sens_edge &= ~(1 << i);
|
|
330 |
bank->sens_edge |= ((value >> 1) & 1) << i;
|
|
331 |
bank->fiq &= ~(1 << i);
|
|
332 |
bank->fiq |= (value & 1) << i;
|
|
324 | 333 |
return; |
325 | 334 |
|
326 | 335 |
case 0x9c: /* ISR */ |
327 | 336 |
for (i = 0; i < 32; i ++) |
328 | 337 |
if (value & (1 << i)) { |
329 |
omap_set_intr(s, i, 1); |
|
338 |
omap_set_intr(s, 32 * bank_no + i, 1);
|
|
330 | 339 |
return; |
331 | 340 |
} |
332 | 341 |
return; |
333 |
|
|
334 |
default: |
|
335 |
OMAP_BAD_REG(addr); |
|
336 | 342 |
} |
343 |
OMAP_BAD_REG(addr); |
|
337 | 344 |
} |
338 | 345 |
|
339 | 346 |
static CPUReadMemoryFunc *omap_inth_readfn[] = { |
... | ... | |
348 | 355 |
omap_inth_write, |
349 | 356 |
}; |
350 | 357 |
|
351 |
static void omap_inth_reset(struct omap_intr_handler_s *s)
|
|
358 |
void omap_inth_reset(struct omap_intr_handler_s *s) |
|
352 | 359 |
{ |
353 |
s->irqs = 0x00000000; |
|
354 |
s->mask = 0xffffffff; |
|
355 |
s->sens_edge = 0x00000000; |
|
356 |
s->fiq = 0x00000000; |
|
357 |
memset(s->priority, 0, sizeof(s->priority)); |
|
358 |
s->new_irq_agr = ~0; |
|
359 |
s->new_fiq_agr = ~0; |
|
360 |
s->sir_irq = 0; |
|
361 |
s->sir_fiq = 0; |
|
360 |
int i; |
|
361 |
|
|
362 |
for (i = 0; i < s->nbanks; ++i){ |
|
363 |
s->banks[i].irqs = 0x00000000; |
|
364 |
s->banks[i].mask = 0xffffffff; |
|
365 |
s->banks[i].sens_edge = 0x00000000; |
|
366 |
s->banks[i].fiq = 0x00000000; |
|
367 |
s->banks[i].inputs = 0x00000000; |
|
368 |
memset(s->banks[i].priority, 0, sizeof(s->banks[i].priority)); |
|
369 |
} |
|
362 | 370 |
|
363 |
omap_inth_update(s); |
|
371 |
s->new_agr[0] = ~0; |
|
372 |
s->new_agr[1] = ~0; |
|
373 |
s->sir_intr[0] = 0; |
|
374 |
s->sir_intr[1] = 0; |
|
375 |
|
|
376 |
qemu_set_irq(s->parent_intr[0], 0); |
|
377 |
qemu_set_irq(s->parent_intr[1], 0); |
|
364 | 378 |
} |
365 | 379 |
|
366 | 380 |
struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base, |
367 |
unsigned long size, qemu_irq parent[2], omap_clk clk) |
|
381 |
unsigned long size, unsigned char nbanks, |
|
382 |
qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk) |
|
368 | 383 |
{ |
369 | 384 |
int iomemtype; |
370 | 385 |
struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) |
371 |
qemu_mallocz(sizeof(struct omap_intr_handler_s)); |
|
386 |
qemu_mallocz(sizeof(struct omap_intr_handler_s) + |
|
387 |
sizeof(struct omap_intr_handler_bank_s) * nbanks); |
|
372 | 388 |
|
373 |
s->parent_pic = parent; |
|
389 |
s->parent_intr[0] = parent_irq; |
|
390 |
s->parent_intr[1] = parent_fiq; |
|
374 | 391 |
s->base = base; |
375 |
s->pins = qemu_allocate_irqs(omap_set_intr, s, 32); |
|
392 |
s->nbanks = nbanks; |
|
393 |
s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32); |
|
394 |
|
|
376 | 395 |
omap_inth_reset(s); |
377 | 396 |
|
378 | 397 |
iomemtype = cpu_register_io_memory(0, omap_inth_readfn, |
... | ... | |
1144 | 1163 |
timer->val = 0; |
1145 | 1164 |
timer->st = 0; |
1146 | 1165 |
if (timer->it_ena) |
1147 |
qemu_irq_raise(timer->irq); |
|
1166 |
/* Edge-triggered irq */ |
|
1167 |
qemu_irq_pulse(timer->irq); |
|
1148 | 1168 |
} |
1149 | 1169 |
} else |
1150 | 1170 |
qemu_del_timer(timer->timer); |
... | ... | |
1161 | 1181 |
} |
1162 | 1182 |
|
1163 | 1183 |
if (timer->it_ena) |
1164 |
qemu_irq_raise(timer->irq); |
|
1184 |
/* Edge-triggered irq */ |
|
1185 |
qemu_irq_pulse(timer->irq); |
|
1165 | 1186 |
omap_timer_update(timer); |
1166 | 1187 |
} |
1167 | 1188 |
|
... | ... | |
3678 | 3699 |
|
3679 | 3700 |
static void omap_rtc_interrupts_update(struct omap_rtc_s *s) |
3680 | 3701 |
{ |
3702 |
/* s->alarm is level-triggered */ |
|
3681 | 3703 |
qemu_set_irq(s->alarm, (s->status >> 6) & 1); |
3682 | 3704 |
} |
3683 | 3705 |
|
... | ... | |
4000 | 4022 |
switch (s->interrupts & 3) { |
4001 | 4023 |
case 0: |
4002 | 4024 |
s->status |= 0x04; |
4003 |
qemu_irq_raise(s->irq);
|
|
4025 |
qemu_irq_pulse(s->irq);
|
|
4004 | 4026 |
break; |
4005 | 4027 |
case 1: |
4006 | 4028 |
if (s->current_tm.tm_sec) |
4007 | 4029 |
break; |
4008 | 4030 |
s->status |= 0x08; |
4009 |
qemu_irq_raise(s->irq);
|
|
4031 |
qemu_irq_pulse(s->irq);
|
|
4010 | 4032 |
break; |
4011 | 4033 |
case 2: |
4012 | 4034 |
if (s->current_tm.tm_sec || s->current_tm.tm_min) |
4013 | 4035 |
break; |
4014 | 4036 |
s->status |= 0x10; |
4015 |
qemu_irq_raise(s->irq);
|
|
4037 |
qemu_irq_pulse(s->irq);
|
|
4016 | 4038 |
break; |
4017 | 4039 |
case 3: |
4018 | 4040 |
if (s->current_tm.tm_sec || |
4019 | 4041 |
s->current_tm.tm_min || s->current_tm.tm_hour) |
4020 | 4042 |
break; |
4021 | 4043 |
s->status |= 0x20; |
4022 |
qemu_irq_raise(s->irq);
|
|
4044 |
qemu_irq_pulse(s->irq);
|
|
4023 | 4045 |
break; |
4024 | 4046 |
} |
4025 | 4047 |
|
... | ... | |
4121 | 4143 |
break; |
4122 | 4144 |
} |
4123 | 4145 |
|
4124 |
qemu_set_irq(s->rxirq, irq); |
|
4146 |
if (irq) |
|
4147 |
qemu_irq_pulse(s->rxirq); |
|
4125 | 4148 |
|
4126 | 4149 |
switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ |
4127 | 4150 |
case 0: |
... | ... | |
4135 | 4158 |
break; |
4136 | 4159 |
} |
4137 | 4160 |
|
4138 |
qemu_set_irq(s->txirq, irq); |
|
4161 |
if (irq) |
|
4162 |
qemu_irq_pulse(s->txirq); |
|
4139 | 4163 |
} |
4140 | 4164 |
|
4141 | 4165 |
static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) |
... | ... | |
4901 | 4925 |
struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) |
4902 | 4926 |
qemu_mallocz(sizeof(struct omap_mpu_state_s)); |
4903 | 4927 |
ram_addr_t imif_base, emiff_base; |
4928 |
qemu_irq *cpu_irq; |
|
4904 | 4929 |
int sdindex; |
4905 |
|
|
4930 |
|
|
4906 | 4931 |
if (!core) |
4907 | 4932 |
core = "ti925t"; |
4908 | 4933 |
|
... | ... | |
4929 | 4954 |
|
4930 | 4955 |
omap_clkm_init(0xfffece00, 0xe1008000, s); |
4931 | 4956 |
|
4932 |
s->ih[0] = omap_inth_init(0xfffecb00, 0x100, |
|
4933 |
arm_pic_init_cpu(s->env), |
|
4957 |
cpu_irq = arm_pic_init_cpu(s->env); |
|
4958 |
s->ih[0] = omap_inth_init(0xfffecb00, 0x100, 1, |
|
4959 |
cpu_irq[ARM_PIC_CPU_IRQ], cpu_irq[ARM_PIC_CPU_FIQ], |
|
4934 | 4960 |
omap_findclk(s, "arminth_ck")); |
4935 |
s->ih[1] = omap_inth_init(0xfffe0000, 0x800, |
|
4936 |
&s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ],
|
|
4961 |
s->ih[1] = omap_inth_init(0xfffe0000, 0x800, 1,
|
|
4962 |
s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ], NULL,
|
|
4937 | 4963 |
omap_findclk(s, "arminth_ck")); |
4938 | 4964 |
s->irq[0] = s->ih[0]->pins; |
4939 | 4965 |
s->irq[1] = s->ih[1]->pins; |
Also available in: Unified diff