]> Git Repo - qemu.git/blob - hw/armv7m_nvic.c
scsi: add channel to addressing
[qemu.git] / hw / armv7m_nvic.c
1 /*
2  * ARM Nested Vectored Interrupt Controller
3  *
4  * Copyright (c) 2006-2007 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licensed under the GPL.
8  *
9  * The ARMv7M System controller is fairly tightly tied in with the
10  * NVIC.  Much of that is also implemented here.
11  */
12
13 #include "sysbus.h"
14 #include "qemu-timer.h"
15 #include "arm-misc.h"
16 #include "exec-memory.h"
17
18 /* 32 internal lines (16 used for system exceptions) plus 64 external
19    interrupt lines.  */
20 #define GIC_NIRQ 96
21 #define NCPU 1
22 #define NVIC 1
23
24 /* Only a single "CPU" interface is present.  */
25 static inline int
26 gic_get_current_cpu(void)
27 {
28     return 0;
29 }
30
31 static uint32_t nvic_readl(void *opaque, uint32_t offset);
32 static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
33
34 #include "arm_gic.c"
35
36 typedef struct {
37     gic_state gic;
38     struct {
39         uint32_t control;
40         uint32_t reload;
41         int64_t tick;
42         QEMUTimer *timer;
43     } systick;
44 } nvic_state;
45
46 /* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
47 #define SYSTICK_SCALE 1000ULL
48
49 #define SYSTICK_ENABLE    (1 << 0)
50 #define SYSTICK_TICKINT   (1 << 1)
51 #define SYSTICK_CLKSOURCE (1 << 2)
52 #define SYSTICK_COUNTFLAG (1 << 16)
53
54 int system_clock_scale;
55
56 /* Conversion factor from qemu timer to SysTick frequencies.  */
57 static inline int64_t systick_scale(nvic_state *s)
58 {
59     if (s->systick.control & SYSTICK_CLKSOURCE)
60         return system_clock_scale;
61     else
62         return 1000;
63 }
64
65 static void systick_reload(nvic_state *s, int reset)
66 {
67     if (reset)
68         s->systick.tick = qemu_get_clock_ns(vm_clock);
69     s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
70     qemu_mod_timer(s->systick.timer, s->systick.tick);
71 }
72
73 static void systick_timer_tick(void * opaque)
74 {
75     nvic_state *s = (nvic_state *)opaque;
76     s->systick.control |= SYSTICK_COUNTFLAG;
77     if (s->systick.control & SYSTICK_TICKINT) {
78         /* Trigger the interrupt.  */
79         armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
80     }
81     if (s->systick.reload == 0) {
82         s->systick.control &= ~SYSTICK_ENABLE;
83     } else {
84         systick_reload(s, 0);
85     }
86 }
87
88 /* The external routines use the hardware vector numbering, ie. the first
89    IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
90 void armv7m_nvic_set_pending(void *opaque, int irq)
91 {
92     nvic_state *s = (nvic_state *)opaque;
93     if (irq >= 16)
94         irq += 16;
95     gic_set_pending_private(&s->gic, 0, irq);
96 }
97
98 /* Make pending IRQ active.  */
99 int armv7m_nvic_acknowledge_irq(void *opaque)
100 {
101     nvic_state *s = (nvic_state *)opaque;
102     uint32_t irq;
103
104     irq = gic_acknowledge_irq(&s->gic, 0);
105     if (irq == 1023)
106         hw_error("Interrupt but no vector\n");
107     if (irq >= 32)
108         irq -= 16;
109     return irq;
110 }
111
112 void armv7m_nvic_complete_irq(void *opaque, int irq)
113 {
114     nvic_state *s = (nvic_state *)opaque;
115     if (irq >= 16)
116         irq += 16;
117     gic_complete_irq(&s->gic, 0, irq);
118 }
119
120 static uint32_t nvic_readl(void *opaque, uint32_t offset)
121 {
122     nvic_state *s = (nvic_state *)opaque;
123     uint32_t val;
124     int irq;
125
126     switch (offset) {
127     case 4: /* Interrupt Control Type.  */
128         return (GIC_NIRQ / 32) - 1;
129     case 0x10: /* SysTick Control and Status.  */
130         val = s->systick.control;
131         s->systick.control &= ~SYSTICK_COUNTFLAG;
132         return val;
133     case 0x14: /* SysTick Reload Value.  */
134         return s->systick.reload;
135     case 0x18: /* SysTick Current Value.  */
136         {
137             int64_t t;
138             if ((s->systick.control & SYSTICK_ENABLE) == 0)
139                 return 0;
140             t = qemu_get_clock_ns(vm_clock);
141             if (t >= s->systick.tick)
142                 return 0;
143             val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
144             /* The interrupt in triggered when the timer reaches zero.
145                However the counter is not reloaded until the next clock
146                tick.  This is a hack to return zero during the first tick.  */
147             if (val > s->systick.reload)
148                 val = 0;
149             return val;
150         }
151     case 0x1c: /* SysTick Calibration Value.  */
152         return 10000;
153     case 0xd00: /* CPUID Base.  */
154         return cpu_single_env->cp15.c0_cpuid;
155     case 0xd04: /* Interrypt Control State.  */
156         /* VECTACTIVE */
157         val = s->gic.running_irq[0];
158         if (val == 1023) {
159             val = 0;
160         } else if (val >= 32) {
161             val -= 16;
162         }
163         /* RETTOBASE */
164         if (s->gic.running_irq[0] == 1023
165                 || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) {
166             val |= (1 << 11);
167         }
168         /* VECTPENDING */
169         if (s->gic.current_pending[0] != 1023)
170             val |= (s->gic.current_pending[0] << 12);
171         /* ISRPENDING */
172         for (irq = 32; irq < GIC_NIRQ; irq++) {
173             if (s->gic.irq_state[irq].pending) {
174                 val |= (1 << 22);
175                 break;
176             }
177         }
178         /* PENDSTSET */
179         if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
180             val |= (1 << 26);
181         /* PENDSVSET */
182         if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
183             val |= (1 << 28);
184         /* NMIPENDSET */
185         if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
186             val |= (1 << 31);
187         return val;
188     case 0xd08: /* Vector Table Offset.  */
189         return cpu_single_env->v7m.vecbase;
190     case 0xd0c: /* Application Interrupt/Reset Control.  */
191         return 0xfa05000;
192     case 0xd10: /* System Control.  */
193         /* TODO: Implement SLEEPONEXIT.  */
194         return 0;
195     case 0xd14: /* Configuration Control.  */
196         /* TODO: Implement Configuration Control bits.  */
197         return 0;
198     case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
199         irq = offset - 0xd14;
200         val = 0;
201         val |= s->gic.priority1[irq++][0];
202         val |= s->gic.priority1[irq++][0] << 8;
203         val |= s->gic.priority1[irq++][0] << 16;
204         val |= s->gic.priority1[irq][0] << 24;
205         return val;
206     case 0xd24: /* System Handler Status.  */
207         val = 0;
208         if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
209         if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
210         if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
211         if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
212         if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
213         if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
214         if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
215         if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
216         if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
217         if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
218         if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
219         if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
220         if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
221         if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
222         return val;
223     case 0xd28: /* Configurable Fault Status.  */
224         /* TODO: Implement Fault Status.  */
225         hw_error("Not implemented: Configurable Fault Status.");
226         return 0;
227     case 0xd2c: /* Hard Fault Status.  */
228     case 0xd30: /* Debug Fault Status.  */
229     case 0xd34: /* Mem Manage Address.  */
230     case 0xd38: /* Bus Fault Address.  */
231     case 0xd3c: /* Aux Fault Status.  */
232         /* TODO: Implement fault status registers.  */
233         goto bad_reg;
234     case 0xd40: /* PFR0.  */
235         return 0x00000030;
236     case 0xd44: /* PRF1.  */
237         return 0x00000200;
238     case 0xd48: /* DFR0.  */
239         return 0x00100000;
240     case 0xd4c: /* AFR0.  */
241         return 0x00000000;
242     case 0xd50: /* MMFR0.  */
243         return 0x00000030;
244     case 0xd54: /* MMFR1.  */
245         return 0x00000000;
246     case 0xd58: /* MMFR2.  */
247         return 0x00000000;
248     case 0xd5c: /* MMFR3.  */
249         return 0x00000000;
250     case 0xd60: /* ISAR0.  */
251         return 0x01141110;
252     case 0xd64: /* ISAR1.  */
253         return 0x02111000;
254     case 0xd68: /* ISAR2.  */
255         return 0x21112231;
256     case 0xd6c: /* ISAR3.  */
257         return 0x01111110;
258     case 0xd70: /* ISAR4.  */
259         return 0x01310102;
260     /* TODO: Implement debug registers.  */
261     default:
262     bad_reg:
263         hw_error("NVIC: Bad read offset 0x%x\n", offset);
264     }
265 }
266
267 static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
268 {
269     nvic_state *s = (nvic_state *)opaque;
270     uint32_t oldval;
271     switch (offset) {
272     case 0x10: /* SysTick Control and Status.  */
273         oldval = s->systick.control;
274         s->systick.control &= 0xfffffff8;
275         s->systick.control |= value & 7;
276         if ((oldval ^ value) & SYSTICK_ENABLE) {
277             int64_t now = qemu_get_clock_ns(vm_clock);
278             if (value & SYSTICK_ENABLE) {
279                 if (s->systick.tick) {
280                     s->systick.tick += now;
281                     qemu_mod_timer(s->systick.timer, s->systick.tick);
282                 } else {
283                     systick_reload(s, 1);
284                 }
285             } else {
286                 qemu_del_timer(s->systick.timer);
287                 s->systick.tick -= now;
288                 if (s->systick.tick < 0)
289                   s->systick.tick = 0;
290             }
291         } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
292             /* This is a hack. Force the timer to be reloaded
293                when the reference clock is changed.  */
294             systick_reload(s, 1);
295         }
296         break;
297     case 0x14: /* SysTick Reload Value.  */
298         s->systick.reload = value;
299         break;
300     case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
301         systick_reload(s, 1);
302         s->systick.control &= ~SYSTICK_COUNTFLAG;
303         break;
304     case 0xd04: /* Interrupt Control State.  */
305         if (value & (1 << 31)) {
306             armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
307         }
308         if (value & (1 << 28)) {
309             armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
310         } else if (value & (1 << 27)) {
311             s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
312             gic_update(&s->gic);
313         }
314         if (value & (1 << 26)) {
315             armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
316         } else if (value & (1 << 25)) {
317             s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
318             gic_update(&s->gic);
319         }
320         break;
321     case 0xd08: /* Vector Table Offset.  */
322         cpu_single_env->v7m.vecbase = value & 0xffffff80;
323         break;
324     case 0xd0c: /* Application Interrupt/Reset Control.  */
325         if ((value >> 16) == 0x05fa) {
326             if (value & 2) {
327                 hw_error("VECTCLRACTIVE not implemented");
328             }
329             if (value & 5) {
330                 hw_error("System reset");
331             }
332         }
333         break;
334     case 0xd10: /* System Control.  */
335     case 0xd14: /* Configuration Control.  */
336         /* TODO: Implement control registers.  */
337         goto bad_reg;
338     case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
339         {
340             int irq;
341             irq = offset - 0xd14;
342             s->gic.priority1[irq++][0] = value & 0xff;
343             s->gic.priority1[irq++][0] = (value >> 8) & 0xff;
344             s->gic.priority1[irq++][0] = (value >> 16) & 0xff;
345             s->gic.priority1[irq][0] = (value >> 24) & 0xff;
346             gic_update(&s->gic);
347         }
348         break;
349     case 0xd24: /* System Handler Control.  */
350         /* TODO: Real hardware allows you to set/clear the active bits
351            under some circumstances.  We don't implement this.  */
352         s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
353         s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
354         s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
355         break;
356     case 0xd28: /* Configurable Fault Status.  */
357     case 0xd2c: /* Hard Fault Status.  */
358     case 0xd30: /* Debug Fault Status.  */
359     case 0xd34: /* Mem Manage Address.  */
360     case 0xd38: /* Bus Fault Address.  */
361     case 0xd3c: /* Aux Fault Status.  */
362         goto bad_reg;
363     default:
364     bad_reg:
365         hw_error("NVIC: Bad write offset 0x%x\n", offset);
366     }
367 }
368
369 static const VMStateDescription vmstate_nvic = {
370     .name = "armv7m_nvic",
371     .version_id = 1,
372     .minimum_version_id = 1,
373     .minimum_version_id_old = 1,
374     .fields      = (VMStateField[]) {
375         VMSTATE_UINT32(systick.control, nvic_state),
376         VMSTATE_UINT32(systick.reload, nvic_state),
377         VMSTATE_INT64(systick.tick, nvic_state),
378         VMSTATE_TIMER(systick.timer, nvic_state),
379         VMSTATE_END_OF_LIST()
380     }
381 };
382
383 static int armv7m_nvic_init(SysBusDevice *dev)
384 {
385     nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
386
387     gic_init(&s->gic);
388     memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
389     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
390     vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
391     return 0;
392 }
393
394 static void armv7m_nvic_register_devices(void)
395 {
396     sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
397 }
398
399 device_init(armv7m_nvic_register_devices)
This page took 0.046113 seconds and 4 git commands to generate.