root / hw / mpcore.c @ 9c9efb6b
History | View | Annotate | Download (10.2 kB)
1 | 9ee6e8bb | pbrook | /*
|
---|---|---|---|
2 | 9ee6e8bb | pbrook | * ARM MPCore internal peripheral emulation.
|
3 | 9ee6e8bb | pbrook | *
|
4 | 9ee6e8bb | pbrook | * Copyright (c) 2006-2007 CodeSourcery.
|
5 | 9ee6e8bb | pbrook | * Written by Paul Brook
|
6 | 9ee6e8bb | pbrook | *
|
7 | 9ee6e8bb | pbrook | * This code is licenced under the GPL.
|
8 | 9ee6e8bb | pbrook | */
|
9 | 9ee6e8bb | pbrook | |
10 | fe7e8758 | Paul Brook | #include "sysbus.h" |
11 | 87ecb68b | pbrook | #include "qemu-timer.h" |
12 | 9ee6e8bb | pbrook | |
13 | 9ee6e8bb | pbrook | #define MPCORE_PRIV_BASE 0x10100000 |
14 | 9ee6e8bb | pbrook | #define NCPU 4 |
15 | 9ee6e8bb | pbrook | /* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
|
16 | 9ee6e8bb | pbrook | (+ 32 internal). However my test chip only exposes/reports 32.
|
17 | 9ee6e8bb | pbrook | More importantly Linux falls over if more than 32 are present! */
|
18 | 9ee6e8bb | pbrook | #define GIC_NIRQ 64 |
19 | 9ee6e8bb | pbrook | |
20 | 9ee6e8bb | pbrook | static inline int |
21 | 9ee6e8bb | pbrook | gic_get_current_cpu(void)
|
22 | 9ee6e8bb | pbrook | { |
23 | 9ee6e8bb | pbrook | return cpu_single_env->cpu_index;
|
24 | 9ee6e8bb | pbrook | } |
25 | 9ee6e8bb | pbrook | |
26 | 9ee6e8bb | pbrook | #include "arm_gic.c" |
27 | 9ee6e8bb | pbrook | |
28 | 9ee6e8bb | pbrook | /* MPCore private memory region. */
|
29 | 9ee6e8bb | pbrook | |
30 | 9ee6e8bb | pbrook | typedef struct { |
31 | 9ee6e8bb | pbrook | uint32_t count; |
32 | 9ee6e8bb | pbrook | uint32_t load; |
33 | 9ee6e8bb | pbrook | uint32_t control; |
34 | 9ee6e8bb | pbrook | uint32_t status; |
35 | 9ee6e8bb | pbrook | uint32_t old_status; |
36 | 9ee6e8bb | pbrook | int64_t tick; |
37 | 9ee6e8bb | pbrook | QEMUTimer *timer; |
38 | 9ee6e8bb | pbrook | struct mpcore_priv_state *mpcore;
|
39 | 9ee6e8bb | pbrook | int id; /* Encodes both timer/watchdog and CPU. */ |
40 | 9ee6e8bb | pbrook | } mpcore_timer_state; |
41 | 9ee6e8bb | pbrook | |
42 | 9ee6e8bb | pbrook | typedef struct mpcore_priv_state { |
43 | fe7e8758 | Paul Brook | gic_state gic; |
44 | 9ee6e8bb | pbrook | uint32_t scu_control; |
45 | fe7e8758 | Paul Brook | int iomemtype;
|
46 | 9ee6e8bb | pbrook | mpcore_timer_state timer[8];
|
47 | c988bfad | Paul Brook | uint32_t num_cpu; |
48 | 9ee6e8bb | pbrook | } mpcore_priv_state; |
49 | 9ee6e8bb | pbrook | |
50 | 9ee6e8bb | pbrook | /* Per-CPU Timers. */
|
51 | 9ee6e8bb | pbrook | |
52 | 9ee6e8bb | pbrook | static inline void mpcore_timer_update_irq(mpcore_timer_state *s) |
53 | 9ee6e8bb | pbrook | { |
54 | 9ee6e8bb | pbrook | if (s->status & ~s->old_status) {
|
55 | fe7e8758 | Paul Brook | gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1)); |
56 | 9ee6e8bb | pbrook | } |
57 | 9ee6e8bb | pbrook | s->old_status = s->status; |
58 | 9ee6e8bb | pbrook | } |
59 | 9ee6e8bb | pbrook | |
60 | 9ee6e8bb | pbrook | /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
|
61 | 9ee6e8bb | pbrook | static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s) |
62 | 9ee6e8bb | pbrook | { |
63 | 9ee6e8bb | pbrook | return (((s->control >> 8) & 0xff) + 1) * 10; |
64 | 9ee6e8bb | pbrook | } |
65 | 9ee6e8bb | pbrook | |
66 | 9ee6e8bb | pbrook | static void mpcore_timer_reload(mpcore_timer_state *s, int restart) |
67 | 9ee6e8bb | pbrook | { |
68 | 9ee6e8bb | pbrook | if (s->count == 0) |
69 | 9ee6e8bb | pbrook | return;
|
70 | 9ee6e8bb | pbrook | if (restart)
|
71 | 9ee6e8bb | pbrook | s->tick = qemu_get_clock(vm_clock); |
72 | 9ee6e8bb | pbrook | s->tick += (int64_t)s->count * mpcore_timer_scale(s); |
73 | 9ee6e8bb | pbrook | qemu_mod_timer(s->timer, s->tick); |
74 | 9ee6e8bb | pbrook | } |
75 | 9ee6e8bb | pbrook | |
76 | 9ee6e8bb | pbrook | static void mpcore_timer_tick(void *opaque) |
77 | 9ee6e8bb | pbrook | { |
78 | 9ee6e8bb | pbrook | mpcore_timer_state *s = (mpcore_timer_state *)opaque; |
79 | 9ee6e8bb | pbrook | s->status = 1;
|
80 | 9ee6e8bb | pbrook | if (s->control & 2) { |
81 | 9ee6e8bb | pbrook | s->count = s->load; |
82 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 0);
|
83 | 9ee6e8bb | pbrook | } else {
|
84 | 9ee6e8bb | pbrook | s->count = 0;
|
85 | 9ee6e8bb | pbrook | } |
86 | 9ee6e8bb | pbrook | mpcore_timer_update_irq(s); |
87 | 9ee6e8bb | pbrook | } |
88 | 9ee6e8bb | pbrook | |
89 | 9ee6e8bb | pbrook | static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset) |
90 | 9ee6e8bb | pbrook | { |
91 | 9ee6e8bb | pbrook | int64_t val; |
92 | 9ee6e8bb | pbrook | switch (offset) {
|
93 | 9ee6e8bb | pbrook | case 0: /* Load */ |
94 | 9ee6e8bb | pbrook | return s->load;
|
95 | 9ee6e8bb | pbrook | /* Fall through. */
|
96 | 9ee6e8bb | pbrook | case 4: /* Counter. */ |
97 | 9ee6e8bb | pbrook | if (((s->control & 1) == 0) || (s->count == 0)) |
98 | 9ee6e8bb | pbrook | return 0; |
99 | 9ee6e8bb | pbrook | /* Slow and ugly, but hopefully won't happen too often. */
|
100 | 9ee6e8bb | pbrook | val = s->tick - qemu_get_clock(vm_clock); |
101 | 9ee6e8bb | pbrook | val /= mpcore_timer_scale(s); |
102 | 9ee6e8bb | pbrook | if (val < 0) |
103 | 9ee6e8bb | pbrook | val = 0;
|
104 | 9ee6e8bb | pbrook | return val;
|
105 | 9ee6e8bb | pbrook | case 8: /* Control. */ |
106 | 9ee6e8bb | pbrook | return s->control;
|
107 | 9ee6e8bb | pbrook | case 12: /* Interrupt status. */ |
108 | 9ee6e8bb | pbrook | return s->status;
|
109 | a38131b6 | blueswir1 | default:
|
110 | a38131b6 | blueswir1 | return 0; |
111 | 9ee6e8bb | pbrook | } |
112 | 9ee6e8bb | pbrook | } |
113 | 9ee6e8bb | pbrook | |
114 | 9ee6e8bb | pbrook | static void mpcore_timer_write(mpcore_timer_state *s, int offset, |
115 | 9ee6e8bb | pbrook | uint32_t value) |
116 | 9ee6e8bb | pbrook | { |
117 | 9ee6e8bb | pbrook | int64_t old; |
118 | 9ee6e8bb | pbrook | switch (offset) {
|
119 | 9ee6e8bb | pbrook | case 0: /* Load */ |
120 | 9ee6e8bb | pbrook | s->load = value; |
121 | 9ee6e8bb | pbrook | /* Fall through. */
|
122 | 9ee6e8bb | pbrook | case 4: /* Counter. */ |
123 | 9ee6e8bb | pbrook | if ((s->control & 1) && s->count) { |
124 | 9ee6e8bb | pbrook | /* Cancel the previous timer. */
|
125 | 9ee6e8bb | pbrook | qemu_del_timer(s->timer); |
126 | 9ee6e8bb | pbrook | } |
127 | 9ee6e8bb | pbrook | s->count = value; |
128 | 9ee6e8bb | pbrook | if (s->control & 1) { |
129 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 1);
|
130 | 9ee6e8bb | pbrook | } |
131 | 9ee6e8bb | pbrook | break;
|
132 | 9ee6e8bb | pbrook | case 8: /* Control. */ |
133 | 9ee6e8bb | pbrook | old = s->control; |
134 | 9ee6e8bb | pbrook | s->control = value; |
135 | 9ee6e8bb | pbrook | if (((old & 1) == 0) && (value & 1)) { |
136 | 9ee6e8bb | pbrook | if (s->count == 0 && (s->control & 2)) |
137 | 9ee6e8bb | pbrook | s->count = s->load; |
138 | 9ee6e8bb | pbrook | mpcore_timer_reload(s, 1);
|
139 | 9ee6e8bb | pbrook | } |
140 | 9ee6e8bb | pbrook | break;
|
141 | 9ee6e8bb | pbrook | case 12: /* Interrupt status. */ |
142 | 9ee6e8bb | pbrook | s->status &= ~value; |
143 | 9ee6e8bb | pbrook | mpcore_timer_update_irq(s); |
144 | 9ee6e8bb | pbrook | break;
|
145 | 9ee6e8bb | pbrook | } |
146 | 9ee6e8bb | pbrook | } |
147 | 9ee6e8bb | pbrook | |
148 | 9ee6e8bb | pbrook | static void mpcore_timer_init(mpcore_priv_state *mpcore, |
149 | 9ee6e8bb | pbrook | mpcore_timer_state *s, int id)
|
150 | 9ee6e8bb | pbrook | { |
151 | 9ee6e8bb | pbrook | s->id = id; |
152 | 9ee6e8bb | pbrook | s->mpcore = mpcore; |
153 | 9ee6e8bb | pbrook | s->timer = qemu_new_timer(vm_clock, mpcore_timer_tick, s); |
154 | 9ee6e8bb | pbrook | } |
155 | 9ee6e8bb | pbrook | |
156 | 9ee6e8bb | pbrook | |
157 | 9ee6e8bb | pbrook | /* Per-CPU private memory mapped IO. */
|
158 | 9ee6e8bb | pbrook | |
159 | c227f099 | Anthony Liguori | static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) |
160 | 9ee6e8bb | pbrook | { |
161 | 9ee6e8bb | pbrook | mpcore_priv_state *s = (mpcore_priv_state *)opaque; |
162 | 9ee6e8bb | pbrook | int id;
|
163 | 9ee6e8bb | pbrook | offset &= 0xfff;
|
164 | 9ee6e8bb | pbrook | if (offset < 0x100) { |
165 | 9ee6e8bb | pbrook | /* SCU */
|
166 | 9ee6e8bb | pbrook | switch (offset) {
|
167 | 9ee6e8bb | pbrook | case 0x00: /* Control. */ |
168 | 9ee6e8bb | pbrook | return s->scu_control;
|
169 | 9ee6e8bb | pbrook | case 0x04: /* Configuration. */ |
170 | c988bfad | Paul Brook | id = ((1 << s->num_cpu) - 1) << 4; |
171 | c988bfad | Paul Brook | return id | (s->num_cpu - 1); |
172 | 9ee6e8bb | pbrook | case 0x08: /* CPU status. */ |
173 | 9ee6e8bb | pbrook | return 0; |
174 | 9ee6e8bb | pbrook | case 0x0c: /* Invalidate all. */ |
175 | 9ee6e8bb | pbrook | return 0; |
176 | 9ee6e8bb | pbrook | default:
|
177 | 9ee6e8bb | pbrook | goto bad_reg;
|
178 | 9ee6e8bb | pbrook | } |
179 | 9ee6e8bb | pbrook | } else if (offset < 0x600) { |
180 | 9ee6e8bb | pbrook | /* Interrupt controller. */
|
181 | 9ee6e8bb | pbrook | if (offset < 0x200) { |
182 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
183 | 9ee6e8bb | pbrook | } else {
|
184 | 9ee6e8bb | pbrook | id = (offset - 0x200) >> 8; |
185 | c988bfad | Paul Brook | if (id >= s->num_cpu) {
|
186 | c988bfad | Paul Brook | return 0; |
187 | c988bfad | Paul Brook | } |
188 | 9ee6e8bb | pbrook | } |
189 | fe7e8758 | Paul Brook | return gic_cpu_read(&s->gic, id, offset & 0xff); |
190 | 9ee6e8bb | pbrook | } else if (offset < 0xb00) { |
191 | 9ee6e8bb | pbrook | /* Timers. */
|
192 | 9ee6e8bb | pbrook | if (offset < 0x700) { |
193 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
194 | 9ee6e8bb | pbrook | } else {
|
195 | 9ee6e8bb | pbrook | id = (offset - 0x700) >> 8; |
196 | c988bfad | Paul Brook | if (id >= s->num_cpu) {
|
197 | c988bfad | Paul Brook | return 0; |
198 | c988bfad | Paul Brook | } |
199 | 9ee6e8bb | pbrook | } |
200 | 9ee6e8bb | pbrook | id <<= 1;
|
201 | 9ee6e8bb | pbrook | if (offset & 0x20) |
202 | 9ee6e8bb | pbrook | id++; |
203 | 9ee6e8bb | pbrook | return mpcore_timer_read(&s->timer[id], offset & 0xf); |
204 | 9ee6e8bb | pbrook | } |
205 | 9ee6e8bb | pbrook | bad_reg:
|
206 | 2ac71179 | Paul Brook | hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); |
207 | 9ee6e8bb | pbrook | return 0; |
208 | 9ee6e8bb | pbrook | } |
209 | 9ee6e8bb | pbrook | |
210 | c227f099 | Anthony Liguori | static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, |
211 | 9ee6e8bb | pbrook | uint32_t value) |
212 | 9ee6e8bb | pbrook | { |
213 | 9ee6e8bb | pbrook | mpcore_priv_state *s = (mpcore_priv_state *)opaque; |
214 | 9ee6e8bb | pbrook | int id;
|
215 | 9ee6e8bb | pbrook | offset &= 0xfff;
|
216 | 9ee6e8bb | pbrook | if (offset < 0x100) { |
217 | 9ee6e8bb | pbrook | /* SCU */
|
218 | 9ee6e8bb | pbrook | switch (offset) {
|
219 | 9ee6e8bb | pbrook | case 0: /* Control register. */ |
220 | 9ee6e8bb | pbrook | s->scu_control = value & 1;
|
221 | 9ee6e8bb | pbrook | break;
|
222 | 9ee6e8bb | pbrook | case 0x0c: /* Invalidate all. */ |
223 | 9ee6e8bb | pbrook | /* This is a no-op as cache is not emulated. */
|
224 | 9ee6e8bb | pbrook | break;
|
225 | 9ee6e8bb | pbrook | default:
|
226 | 9ee6e8bb | pbrook | goto bad_reg;
|
227 | 9ee6e8bb | pbrook | } |
228 | 9ee6e8bb | pbrook | } else if (offset < 0x600) { |
229 | 9ee6e8bb | pbrook | /* Interrupt controller. */
|
230 | 9ee6e8bb | pbrook | if (offset < 0x200) { |
231 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
232 | 9ee6e8bb | pbrook | } else {
|
233 | 9ee6e8bb | pbrook | id = (offset - 0x200) >> 8; |
234 | 9ee6e8bb | pbrook | } |
235 | c988bfad | Paul Brook | if (id < s->num_cpu) {
|
236 | c988bfad | Paul Brook | gic_cpu_write(&s->gic, id, offset & 0xff, value);
|
237 | c988bfad | Paul Brook | } |
238 | 9ee6e8bb | pbrook | } else if (offset < 0xb00) { |
239 | 9ee6e8bb | pbrook | /* Timers. */
|
240 | 9ee6e8bb | pbrook | if (offset < 0x700) { |
241 | 9ee6e8bb | pbrook | id = gic_get_current_cpu(); |
242 | 9ee6e8bb | pbrook | } else {
|
243 | 9ee6e8bb | pbrook | id = (offset - 0x700) >> 8; |
244 | 9ee6e8bb | pbrook | } |
245 | c988bfad | Paul Brook | if (id < s->num_cpu) {
|
246 | c988bfad | Paul Brook | id <<= 1;
|
247 | c988bfad | Paul Brook | if (offset & 0x20) |
248 | c988bfad | Paul Brook | id++; |
249 | c988bfad | Paul Brook | mpcore_timer_write(&s->timer[id], offset & 0xf, value);
|
250 | c988bfad | Paul Brook | } |
251 | 9ee6e8bb | pbrook | return;
|
252 | 9ee6e8bb | pbrook | } |
253 | 9ee6e8bb | pbrook | return;
|
254 | 9ee6e8bb | pbrook | bad_reg:
|
255 | 2ac71179 | Paul Brook | hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset); |
256 | 9ee6e8bb | pbrook | } |
257 | 9ee6e8bb | pbrook | |
258 | d60efc6b | Blue Swirl | static CPUReadMemoryFunc * const mpcore_priv_readfn[] = { |
259 | 9ee6e8bb | pbrook | mpcore_priv_read, |
260 | 9ee6e8bb | pbrook | mpcore_priv_read, |
261 | 9ee6e8bb | pbrook | mpcore_priv_read |
262 | 9ee6e8bb | pbrook | }; |
263 | 9ee6e8bb | pbrook | |
264 | d60efc6b | Blue Swirl | static CPUWriteMemoryFunc * const mpcore_priv_writefn[] = { |
265 | 9ee6e8bb | pbrook | mpcore_priv_write, |
266 | 9ee6e8bb | pbrook | mpcore_priv_write, |
267 | 9ee6e8bb | pbrook | mpcore_priv_write |
268 | 9ee6e8bb | pbrook | }; |
269 | 9ee6e8bb | pbrook | |
270 | c227f099 | Anthony Liguori | static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base) |
271 | fe7e8758 | Paul Brook | { |
272 | fe7e8758 | Paul Brook | mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); |
273 | fe7e8758 | Paul Brook | cpu_register_physical_memory(base, 0x1000, s->iomemtype);
|
274 | fe7e8758 | Paul Brook | cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype); |
275 | fe7e8758 | Paul Brook | } |
276 | 9ee6e8bb | pbrook | |
277 | 81a322d4 | Gerd Hoffmann | static int mpcore_priv_init(SysBusDevice *dev) |
278 | 9ee6e8bb | pbrook | { |
279 | fe7e8758 | Paul Brook | mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); |
280 | 9ee6e8bb | pbrook | int i;
|
281 | 9ee6e8bb | pbrook | |
282 | c988bfad | Paul Brook | gic_init(&s->gic, s->num_cpu); |
283 | 1eed09cb | Avi Kivity | s->iomemtype = cpu_register_io_memory(mpcore_priv_readfn, |
284 | fe7e8758 | Paul Brook | mpcore_priv_writefn, s); |
285 | fe7e8758 | Paul Brook | sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map);
|
286 | c988bfad | Paul Brook | for (i = 0; i < s->num_cpu * 2; i++) { |
287 | 9ee6e8bb | pbrook | mpcore_timer_init(s, &s->timer[i], i); |
288 | 9ee6e8bb | pbrook | } |
289 | 81a322d4 | Gerd Hoffmann | return 0; |
290 | 9ee6e8bb | pbrook | } |
291 | 9ee6e8bb | pbrook | |
292 | 9ee6e8bb | pbrook | /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
|
293 | 9ee6e8bb | pbrook | controllers. The output of these, plus some of the raw input lines
|
294 | 9ee6e8bb | pbrook | are fed into a single SMP-aware interrupt controller on the CPU. */
|
295 | 9ee6e8bb | pbrook | typedef struct { |
296 | fe7e8758 | Paul Brook | SysBusDevice busdev; |
297 | fe7e8758 | Paul Brook | qemu_irq cpuic[32];
|
298 | fe7e8758 | Paul Brook | qemu_irq rvic[4][64]; |
299 | c988bfad | Paul Brook | uint32_t num_cpu; |
300 | 9ee6e8bb | pbrook | } mpcore_rirq_state; |
301 | 9ee6e8bb | pbrook | |
302 | 9ee6e8bb | pbrook | /* Map baseboard IRQs onto CPU IRQ lines. */
|
303 | 9ee6e8bb | pbrook | static const int mpcore_irq_map[32] = { |
304 | 9ee6e8bb | pbrook | -1, -1, -1, -1, 1, 2, -1, -1, |
305 | 9ee6e8bb | pbrook | -1, -1, 6, -1, 4, 5, -1, -1, |
306 | 9ee6e8bb | pbrook | -1, 14, 15, 0, 7, 8, -1, -1, |
307 | 9ee6e8bb | pbrook | -1, -1, -1, -1, 9, 3, -1, -1, |
308 | 9ee6e8bb | pbrook | }; |
309 | 9ee6e8bb | pbrook | |
310 | 9ee6e8bb | pbrook | static void mpcore_rirq_set_irq(void *opaque, int irq, int level) |
311 | 9ee6e8bb | pbrook | { |
312 | 9ee6e8bb | pbrook | mpcore_rirq_state *s = (mpcore_rirq_state *)opaque; |
313 | 9ee6e8bb | pbrook | int i;
|
314 | 9ee6e8bb | pbrook | |
315 | 9ee6e8bb | pbrook | for (i = 0; i < 4; i++) { |
316 | 9ee6e8bb | pbrook | qemu_set_irq(s->rvic[i][irq], level); |
317 | 9ee6e8bb | pbrook | } |
318 | 9ee6e8bb | pbrook | if (irq < 32) { |
319 | 9ee6e8bb | pbrook | irq = mpcore_irq_map[irq]; |
320 | 9ee6e8bb | pbrook | if (irq >= 0) { |
321 | 9ee6e8bb | pbrook | qemu_set_irq(s->cpuic[irq], level); |
322 | 9ee6e8bb | pbrook | } |
323 | 9ee6e8bb | pbrook | } |
324 | 9ee6e8bb | pbrook | } |
325 | 9ee6e8bb | pbrook | |
326 | 81a322d4 | Gerd Hoffmann | static int realview_mpcore_init(SysBusDevice *dev) |
327 | 9ee6e8bb | pbrook | { |
328 | fe7e8758 | Paul Brook | mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
329 | fe7e8758 | Paul Brook | DeviceState *gic; |
330 | fe7e8758 | Paul Brook | DeviceState *priv; |
331 | c988bfad | Paul Brook | SysBusDevice *bus_priv; |
332 | 9ee6e8bb | pbrook | int n;
|
333 | fe7e8758 | Paul Brook | int i;
|
334 | 9ee6e8bb | pbrook | |
335 | c988bfad | Paul Brook | priv = qdev_create(NULL, "arm11mpcore_priv"); |
336 | c988bfad | Paul Brook | qdev_prop_set_uint32(priv, "num-cpu", s->num_cpu);
|
337 | c988bfad | Paul Brook | qdev_init_nofail(priv); |
338 | c988bfad | Paul Brook | bus_priv = sysbus_from_qdev(priv); |
339 | c988bfad | Paul Brook | sysbus_mmio_map(bus_priv, 0, MPCORE_PRIV_BASE);
|
340 | c988bfad | Paul Brook | sysbus_pass_irq(dev, bus_priv); |
341 | fe7e8758 | Paul Brook | for (i = 0; i < 32; i++) { |
342 | 067a3ddc | Paul Brook | s->cpuic[i] = qdev_get_gpio_in(priv, i); |
343 | fe7e8758 | Paul Brook | } |
344 | 9ee6e8bb | pbrook | /* ??? IRQ routing is hardcoded to "normal" mode. */
|
345 | 9ee6e8bb | pbrook | for (n = 0; n < 4; n++) { |
346 | fe7e8758 | Paul Brook | gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
347 | fe7e8758 | Paul Brook | s->cpuic[10 + n]);
|
348 | fe7e8758 | Paul Brook | for (i = 0; i < 64; i++) { |
349 | 067a3ddc | Paul Brook | s->rvic[n][i] = qdev_get_gpio_in(gic, i); |
350 | fe7e8758 | Paul Brook | } |
351 | 9ee6e8bb | pbrook | } |
352 | 067a3ddc | Paul Brook | qdev_init_gpio_in(&dev->qdev, mpcore_rirq_set_irq, 64);
|
353 | 81a322d4 | Gerd Hoffmann | return 0; |
354 | 9ee6e8bb | pbrook | } |
355 | fe7e8758 | Paul Brook | |
356 | c988bfad | Paul Brook | static SysBusDeviceInfo mpcore_rirq_info = {
|
357 | c988bfad | Paul Brook | .init = realview_mpcore_init, |
358 | c988bfad | Paul Brook | .qdev.name = "realview_mpcore",
|
359 | c988bfad | Paul Brook | .qdev.size = sizeof(mpcore_rirq_state),
|
360 | c988bfad | Paul Brook | .qdev.props = (Property[]) { |
361 | c988bfad | Paul Brook | DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1), |
362 | c988bfad | Paul Brook | DEFINE_PROP_END_OF_LIST(), |
363 | c988bfad | Paul Brook | } |
364 | c988bfad | Paul Brook | }; |
365 | c988bfad | Paul Brook | |
366 | c988bfad | Paul Brook | static SysBusDeviceInfo mpcore_priv_info = {
|
367 | c988bfad | Paul Brook | .init = mpcore_priv_init, |
368 | c988bfad | Paul Brook | .qdev.name = "arm11mpcore_priv",
|
369 | c988bfad | Paul Brook | .qdev.size = sizeof(mpcore_priv_state),
|
370 | c988bfad | Paul Brook | .qdev.props = (Property[]) { |
371 | c988bfad | Paul Brook | DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1), |
372 | c988bfad | Paul Brook | DEFINE_PROP_END_OF_LIST(), |
373 | c988bfad | Paul Brook | } |
374 | c988bfad | Paul Brook | }; |
375 | c988bfad | Paul Brook | |
376 | fe7e8758 | Paul Brook | static void mpcore_register_devices(void) |
377 | fe7e8758 | Paul Brook | { |
378 | c988bfad | Paul Brook | sysbus_register_withprop(&mpcore_rirq_info); |
379 | c988bfad | Paul Brook | sysbus_register_withprop(&mpcore_priv_info); |
380 | fe7e8758 | Paul Brook | } |
381 | fe7e8758 | Paul Brook | |
382 | fe7e8758 | Paul Brook | device_init(mpcore_register_devices) |