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;
|