xref: /qemu/hw/arm/integratorcp.c (revision bd2be1500337f0349f70802e4d8d43f5aca61477)
1b5ff1b31Sbellard /*
2b5ff1b31Sbellard  * ARM Integrator CP System emulation.
3b5ff1b31Sbellard  *
4a1bb27b1Spbrook  * Copyright (c) 2005-2007 CodeSourcery.
5b5ff1b31Sbellard  * Written by Paul Brook
6b5ff1b31Sbellard  *
78e31bf38SMatthew Fernandez  * This code is licensed under the GPL
8b5ff1b31Sbellard  */
9b5ff1b31Sbellard 
1083c9f4caSPaolo Bonzini #include "hw/sysbus.h"
11*bd2be150SPeter Maydell #include "hw/devices.h"
1283c9f4caSPaolo Bonzini #include "hw/boards.h"
13*bd2be150SPeter Maydell #include "hw/arm/arm.h"
141422e32dSPaolo Bonzini #include "net/net.h"
15022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
169c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
17b5ff1b31Sbellard 
18b5ff1b31Sbellard typedef struct {
19a7086888SPaul Brook     SysBusDevice busdev;
2071d9bc50SBenoît Canet     MemoryRegion iomem;
21ee6847d1SGerd Hoffmann     uint32_t memsz;
22211adf4dSAvi Kivity     MemoryRegion flash;
23b5ff1b31Sbellard     uint32_t cm_osc;
24b5ff1b31Sbellard     uint32_t cm_ctrl;
25b5ff1b31Sbellard     uint32_t cm_lock;
26b5ff1b31Sbellard     uint32_t cm_auxosc;
27b5ff1b31Sbellard     uint32_t cm_sdram;
28b5ff1b31Sbellard     uint32_t cm_init;
29b5ff1b31Sbellard     uint32_t cm_flags;
30b5ff1b31Sbellard     uint32_t cm_nvflags;
31b5ff1b31Sbellard     uint32_t int_level;
32b5ff1b31Sbellard     uint32_t irq_enabled;
33b5ff1b31Sbellard     uint32_t fiq_enabled;
34b5ff1b31Sbellard } integratorcm_state;
35b5ff1b31Sbellard 
36b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
37b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
38b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
39b5ff1b31Sbellard };
40b5ff1b31Sbellard 
41a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
4271d9bc50SBenoît Canet                                   unsigned size)
43b5ff1b31Sbellard {
44b5ff1b31Sbellard     integratorcm_state *s = (integratorcm_state *)opaque;
45b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
46b5ff1b31Sbellard         /* CM_SPD */
47b5ff1b31Sbellard         if (offset >= 0x180)
48b5ff1b31Sbellard             return 0;
49b5ff1b31Sbellard         return integrator_spd[offset >> 2];
50b5ff1b31Sbellard     }
51b5ff1b31Sbellard     switch (offset >> 2) {
52b5ff1b31Sbellard     case 0: /* CM_ID */
53b5ff1b31Sbellard         return 0x411a3001;
54b5ff1b31Sbellard     case 1: /* CM_PROC */
55b5ff1b31Sbellard         return 0;
56b5ff1b31Sbellard     case 2: /* CM_OSC */
57b5ff1b31Sbellard         return s->cm_osc;
58b5ff1b31Sbellard     case 3: /* CM_CTRL */
59b5ff1b31Sbellard         return s->cm_ctrl;
60b5ff1b31Sbellard     case 4: /* CM_STAT */
61b5ff1b31Sbellard         return 0x00100000;
62b5ff1b31Sbellard     case 5: /* CM_LOCK */
63b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
64b5ff1b31Sbellard             return 0x1a05f;
65b5ff1b31Sbellard         } else {
66b5ff1b31Sbellard             return s->cm_lock;
67b5ff1b31Sbellard         }
68b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
69b5ff1b31Sbellard         /* ??? High frequency timer.  */
702ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
71b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
72b5ff1b31Sbellard         return s->cm_auxosc;
73b5ff1b31Sbellard     case 8: /* CM_SDRAM */
74b5ff1b31Sbellard         return s->cm_sdram;
75b5ff1b31Sbellard     case 9: /* CM_INIT */
76b5ff1b31Sbellard         return s->cm_init;
77b5ff1b31Sbellard     case 10: /* CM_REFCT */
78b5ff1b31Sbellard         /* ??? High frequency timer.  */
792ac71179SPaul Brook         hw_error("integratorcm_read: CM_REFCT");
80b5ff1b31Sbellard     case 12: /* CM_FLAGS */
81b5ff1b31Sbellard         return s->cm_flags;
82b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
83b5ff1b31Sbellard         return s->cm_nvflags;
84b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
85b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
86b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
87b5ff1b31Sbellard         return s->int_level;
88b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
89b5ff1b31Sbellard         return s->irq_enabled;
90b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
91b5ff1b31Sbellard         return s->int_level & 1;
92b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
93b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
94b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
95b5ff1b31Sbellard         return s->int_level;
96b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
97b5ff1b31Sbellard         return s->fiq_enabled;
98b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
99b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
100b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
101b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
102b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
103b5ff1b31Sbellard         return 0;
104b5ff1b31Sbellard     default:
1052ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1062ac71179SPaul Brook                  (int)offset);
107b5ff1b31Sbellard         return 0;
108b5ff1b31Sbellard     }
109b5ff1b31Sbellard }
110b5ff1b31Sbellard 
111563c2bf3SPeter Maydell static void integratorcm_do_remap(integratorcm_state *s)
112b5ff1b31Sbellard {
113563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
114563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
115563c2bf3SPeter Maydell      */
116563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
117b5ff1b31Sbellard }
118b5ff1b31Sbellard 
119b5ff1b31Sbellard static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
120b5ff1b31Sbellard {
121b5ff1b31Sbellard     if (value & 8) {
122df3f457bSPeter Maydell         qemu_system_reset_request();
123b5ff1b31Sbellard     }
124df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
125df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
126df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
127df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
128df3f457bSPeter Maydell          * will swamp anything else on the terminal.
129df3f457bSPeter Maydell          */
130b5ff1b31Sbellard     }
131df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
132df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
133563c2bf3SPeter Maydell     integratorcm_do_remap(s);
134b5ff1b31Sbellard }
135b5ff1b31Sbellard 
136b5ff1b31Sbellard static void integratorcm_update(integratorcm_state *s)
137b5ff1b31Sbellard {
138b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
139b5ff1b31Sbellard        are active.  */
140b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1412ac71179SPaul Brook         hw_error("Core module interrupt\n");
142b5ff1b31Sbellard }
143b5ff1b31Sbellard 
144a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
14571d9bc50SBenoît Canet                                uint64_t value, unsigned size)
146b5ff1b31Sbellard {
147b5ff1b31Sbellard     integratorcm_state *s = (integratorcm_state *)opaque;
148b5ff1b31Sbellard     switch (offset >> 2) {
149b5ff1b31Sbellard     case 2: /* CM_OSC */
150b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
151b5ff1b31Sbellard             s->cm_osc = value;
152b5ff1b31Sbellard         break;
153b5ff1b31Sbellard     case 3: /* CM_CTRL */
154b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
155b5ff1b31Sbellard         break;
156b5ff1b31Sbellard     case 5: /* CM_LOCK */
157b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
158b5ff1b31Sbellard         break;
159b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
160b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
161b5ff1b31Sbellard             s->cm_auxosc = value;
162b5ff1b31Sbellard         break;
163b5ff1b31Sbellard     case 8: /* CM_SDRAM */
164b5ff1b31Sbellard         s->cm_sdram = value;
165b5ff1b31Sbellard         break;
166b5ff1b31Sbellard     case 9: /* CM_INIT */
167b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
168b5ff1b31Sbellard         s->cm_init = value;
169b5ff1b31Sbellard         break;
170b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
171b5ff1b31Sbellard         s->cm_flags |= value;
172b5ff1b31Sbellard         break;
173b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
174b5ff1b31Sbellard         s->cm_flags &= ~value;
175b5ff1b31Sbellard         break;
176b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
177b5ff1b31Sbellard         s->cm_nvflags |= value;
178b5ff1b31Sbellard         break;
179b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
180b5ff1b31Sbellard         s->cm_nvflags &= ~value;
181b5ff1b31Sbellard         break;
182b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
183b5ff1b31Sbellard         s->irq_enabled |= value;
184b5ff1b31Sbellard         integratorcm_update(s);
185b5ff1b31Sbellard         break;
186b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
187b5ff1b31Sbellard         s->irq_enabled &= ~value;
188b5ff1b31Sbellard         integratorcm_update(s);
189b5ff1b31Sbellard         break;
190b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
191b5ff1b31Sbellard         s->int_level |= (value & 1);
192b5ff1b31Sbellard         integratorcm_update(s);
193b5ff1b31Sbellard         break;
194b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
195b5ff1b31Sbellard         s->int_level &= ~(value & 1);
196b5ff1b31Sbellard         integratorcm_update(s);
197b5ff1b31Sbellard         break;
198b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
199b5ff1b31Sbellard         s->fiq_enabled |= value;
200b5ff1b31Sbellard         integratorcm_update(s);
201b5ff1b31Sbellard         break;
202b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
203b5ff1b31Sbellard         s->fiq_enabled &= ~value;
204b5ff1b31Sbellard         integratorcm_update(s);
205b5ff1b31Sbellard         break;
206b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
207b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
208b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
209b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
210b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
211b5ff1b31Sbellard         break;
212b5ff1b31Sbellard     default:
2132ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2142ac71179SPaul Brook                  (int)offset);
215b5ff1b31Sbellard         break;
216b5ff1b31Sbellard     }
217b5ff1b31Sbellard }
218b5ff1b31Sbellard 
219b5ff1b31Sbellard /* Integrator/CM control registers.  */
220b5ff1b31Sbellard 
22171d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
22271d9bc50SBenoît Canet     .read = integratorcm_read,
22371d9bc50SBenoît Canet     .write = integratorcm_write,
22471d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
225b5ff1b31Sbellard };
226b5ff1b31Sbellard 
22781a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
228b5ff1b31Sbellard {
229a7086888SPaul Brook     integratorcm_state *s = FROM_SYSBUS(integratorcm_state, dev);
230b5ff1b31Sbellard 
231b5ff1b31Sbellard     s->cm_osc = 0x01000048;
232b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
233b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
234b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
235ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
236b5ff1b31Sbellard         integrator_spd[31] = 64;
237b5ff1b31Sbellard         s->cm_sdram |= 0x10;
238ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
239b5ff1b31Sbellard         integrator_spd[31] = 32;
240b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
241ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
242b5ff1b31Sbellard         integrator_spd[31] = 16;
243b5ff1b31Sbellard         s->cm_sdram |= 0x08;
244ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
245b5ff1b31Sbellard         integrator_spd[31] = 4;
246b5ff1b31Sbellard         s->cm_sdram |= 0x04;
247b5ff1b31Sbellard     } else {
248b5ff1b31Sbellard         integrator_spd[31] = 2;
249b5ff1b31Sbellard     }
250b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
251b5ff1b31Sbellard     s->cm_init = 0x00000112;
252c5705a77SAvi Kivity     memory_region_init_ram(&s->flash, "integrator.flash", 0x100000);
253c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
254b5ff1b31Sbellard 
25571d9bc50SBenoît Canet     memory_region_init_io(&s->iomem, &integratorcm_ops, s,
25671d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
257750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
25871d9bc50SBenoît Canet 
259563c2bf3SPeter Maydell     integratorcm_do_remap(s);
260b5ff1b31Sbellard     /* ??? Save/restore.  */
26181a322d4SGerd Hoffmann     return 0;
262b5ff1b31Sbellard }
263b5ff1b31Sbellard 
264b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
265b5ff1b31Sbellard /* Primary interrupt controller.  */
266b5ff1b31Sbellard 
267b5ff1b31Sbellard typedef struct icp_pic_state
268b5ff1b31Sbellard {
269a7086888SPaul Brook   SysBusDevice busdev;
27061074e46SBenoît Canet   MemoryRegion iomem;
271b5ff1b31Sbellard   uint32_t level;
272b5ff1b31Sbellard   uint32_t irq_enabled;
273b5ff1b31Sbellard   uint32_t fiq_enabled;
274d537cf6cSpbrook   qemu_irq parent_irq;
275d537cf6cSpbrook   qemu_irq parent_fiq;
276b5ff1b31Sbellard } icp_pic_state;
277b5ff1b31Sbellard 
278b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
279b5ff1b31Sbellard {
280b5ff1b31Sbellard     uint32_t flags;
281b5ff1b31Sbellard 
282b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
283d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
284cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
285d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
286b5ff1b31Sbellard }
287b5ff1b31Sbellard 
288cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
289b5ff1b31Sbellard {
29080337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
291b5ff1b31Sbellard     if (level)
29280337b66Sbellard         s->level |= 1 << irq;
293b5ff1b31Sbellard     else
29480337b66Sbellard         s->level &= ~(1 << irq);
295b5ff1b31Sbellard     icp_pic_update(s);
296b5ff1b31Sbellard }
297b5ff1b31Sbellard 
298a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
29961074e46SBenoît Canet                              unsigned size)
300b5ff1b31Sbellard {
301b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
302b5ff1b31Sbellard 
303b5ff1b31Sbellard     switch (offset >> 2) {
304b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
305b5ff1b31Sbellard         return s->level & s->irq_enabled;
306b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
307b5ff1b31Sbellard         return s->level;
308b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
309b5ff1b31Sbellard         return s->irq_enabled;
310b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
311b5ff1b31Sbellard         return s->level & 1;
312b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
313b5ff1b31Sbellard         return s->level & s->fiq_enabled;
314b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
315b5ff1b31Sbellard         return s->level;
316b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
317b5ff1b31Sbellard         return s->fiq_enabled;
318b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
319b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
320b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
321b5ff1b31Sbellard     default:
32229bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
323b5ff1b31Sbellard         return 0;
324b5ff1b31Sbellard     }
325b5ff1b31Sbellard }
326b5ff1b31Sbellard 
327a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
32861074e46SBenoît Canet                           uint64_t value, unsigned size)
329b5ff1b31Sbellard {
330b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
331b5ff1b31Sbellard 
332b5ff1b31Sbellard     switch (offset >> 2) {
333b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
334b5ff1b31Sbellard         s->irq_enabled |= value;
335b5ff1b31Sbellard         break;
336b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
337b5ff1b31Sbellard         s->irq_enabled &= ~value;
338b5ff1b31Sbellard         break;
339b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
340b5ff1b31Sbellard         if (value & 1)
341d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
342b5ff1b31Sbellard         break;
343b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
344b5ff1b31Sbellard         if (value & 1)
345d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
346b5ff1b31Sbellard         break;
347b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
348b5ff1b31Sbellard         s->fiq_enabled |= value;
349b5ff1b31Sbellard         break;
350b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
351b5ff1b31Sbellard         s->fiq_enabled &= ~value;
352b5ff1b31Sbellard         break;
353b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
354b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
355b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
356b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
357b5ff1b31Sbellard     default:
35829bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
359b5ff1b31Sbellard         return;
360b5ff1b31Sbellard     }
361b5ff1b31Sbellard     icp_pic_update(s);
362b5ff1b31Sbellard }
363b5ff1b31Sbellard 
36461074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
36561074e46SBenoît Canet     .read = icp_pic_read,
36661074e46SBenoît Canet     .write = icp_pic_write,
36761074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
368b5ff1b31Sbellard };
369b5ff1b31Sbellard 
37081a322d4SGerd Hoffmann static int icp_pic_init(SysBusDevice *dev)
371b5ff1b31Sbellard {
372a7086888SPaul Brook     icp_pic_state *s = FROM_SYSBUS(icp_pic_state, dev);
373b5ff1b31Sbellard 
374067a3ddcSPaul Brook     qdev_init_gpio_in(&dev->qdev, icp_pic_set_irq, 32);
375a7086888SPaul Brook     sysbus_init_irq(dev, &s->parent_irq);
376a7086888SPaul Brook     sysbus_init_irq(dev, &s->parent_fiq);
37761074e46SBenoît Canet     memory_region_init_io(&s->iomem, &icp_pic_ops, s, "icp-pic", 0x00800000);
378750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
37981a322d4SGerd Hoffmann     return 0;
380b5ff1b31Sbellard }
381b5ff1b31Sbellard 
382b5ff1b31Sbellard /* CP control registers.  */
3830c36493eSBenoît Canet 
384a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
3850c36493eSBenoît Canet                                  unsigned size)
386b5ff1b31Sbellard {
387b5ff1b31Sbellard     switch (offset >> 2) {
388b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
389b5ff1b31Sbellard         return 0x41034003;
390b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
391b5ff1b31Sbellard         return 0;
392b5ff1b31Sbellard     case 2: /* CP_INTREG */
393b5ff1b31Sbellard         return 0;
394b5ff1b31Sbellard     case 3: /* CP_DECODE */
395b5ff1b31Sbellard         return 0x11;
396b5ff1b31Sbellard     default:
3972ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
398b5ff1b31Sbellard         return 0;
399b5ff1b31Sbellard     }
400b5ff1b31Sbellard }
401b5ff1b31Sbellard 
402a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4030c36493eSBenoît Canet                           uint64_t value, unsigned size)
404b5ff1b31Sbellard {
405b5ff1b31Sbellard     switch (offset >> 2) {
406b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
407b5ff1b31Sbellard     case 2: /* CP_INTREG */
408b5ff1b31Sbellard     case 3: /* CP_DECODE */
409b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
410b5ff1b31Sbellard         break;
411b5ff1b31Sbellard     default:
4122ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
413b5ff1b31Sbellard     }
414b5ff1b31Sbellard }
4150c36493eSBenoît Canet 
4160c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4170c36493eSBenoît Canet     .read = icp_control_read,
4180c36493eSBenoît Canet     .write = icp_control_write,
4190c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
420b5ff1b31Sbellard };
421b5ff1b31Sbellard 
422a8170e5eSAvi Kivity static void icp_control_init(hwaddr base)
423b5ff1b31Sbellard {
4240c36493eSBenoît Canet     MemoryRegion *io;
425b5ff1b31Sbellard 
4260c36493eSBenoît Canet     io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
4270c36493eSBenoît Canet     memory_region_init_io(io, &icp_control_ops, NULL,
4280c36493eSBenoît Canet                           "control", 0x00800000);
4290c36493eSBenoît Canet     memory_region_add_subregion(get_system_memory(), base, io);
430b5ff1b31Sbellard     /* ??? Save/restore.  */
431b5ff1b31Sbellard }
432b5ff1b31Sbellard 
433b5ff1b31Sbellard 
434b5ff1b31Sbellard /* Board init.  */
435b5ff1b31Sbellard 
436f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
437f93eb9ffSbalrog     .loader_start = 0x0,
438f93eb9ffSbalrog     .board_id = 0x113,
439f93eb9ffSbalrog };
440f93eb9ffSbalrog 
4415f072e1fSEduardo Habkost static void integratorcp_init(QEMUMachineInitArgs *args)
442b5ff1b31Sbellard {
4435f072e1fSEduardo Habkost     ram_addr_t ram_size = args->ram_size;
4445f072e1fSEduardo Habkost     const char *cpu_model = args->cpu_model;
4455f072e1fSEduardo Habkost     const char *kernel_filename = args->kernel_filename;
4465f072e1fSEduardo Habkost     const char *kernel_cmdline = args->kernel_cmdline;
4475f072e1fSEduardo Habkost     const char *initrd_filename = args->initrd_filename;
448393a9eabSAndreas Färber     ARMCPU *cpu;
449211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
450211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
451211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
452a7086888SPaul Brook     qemu_irq pic[32];
453d537cf6cSpbrook     qemu_irq *cpu_pic;
454a7086888SPaul Brook     DeviceState *dev;
455a7086888SPaul Brook     int i;
456b5ff1b31Sbellard 
457393a9eabSAndreas Färber     if (!cpu_model) {
4583371d272Spbrook         cpu_model = "arm926";
459393a9eabSAndreas Färber     }
460393a9eabSAndreas Färber     cpu = cpu_arm_init(cpu_model);
461393a9eabSAndreas Färber     if (!cpu) {
462aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
463aaed909aSbellard         exit(1);
464aaed909aSbellard     }
465393a9eabSAndreas Färber 
466c5705a77SAvi Kivity     memory_region_init_ram(ram, "integrator.ram", ram_size);
467c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
468b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
4691235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
470b5ff1b31Sbellard     /* SDRAM at address zero*/
471211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
472b5ff1b31Sbellard     /* And again at address 0x80000000 */
473211adf4dSAvi Kivity     memory_region_init_alias(ram_alias, "ram.alias", ram, 0, ram_size);
474211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
475b5ff1b31Sbellard 
476a7086888SPaul Brook     dev = qdev_create(NULL, "integrator_core");
477ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
478e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
479a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
480a7086888SPaul Brook 
4814bd74661SAndreas Färber     cpu_pic = arm_pic_init_cpu(cpu);
482a7086888SPaul Brook     dev = sysbus_create_varargs("integrator_pic", 0x14000000,
483a7086888SPaul Brook                                 cpu_pic[ARM_PIC_CPU_IRQ],
484a7086888SPaul Brook                                 cpu_pic[ARM_PIC_CPU_FIQ], NULL);
485a7086888SPaul Brook     for (i = 0; i < 32; i++) {
486067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
487a7086888SPaul Brook     }
4886a824ec3SPaul Brook     sysbus_create_simple("integrator_pic", 0xca000000, pic[26]);
4896a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
4906a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
491a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
492a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
493a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
494b5ff1b31Sbellard     icp_control_init(0xcb000000);
49586394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
49686394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
497aa9311d8SPaul Brook     sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
498a005d073SStefan Hajnoczi     if (nd_table[0].used)
499d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
5002e9bdce5SPaul Brook 
5012e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
502b5ff1b31Sbellard 
503f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
504f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
505f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
506f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
5073aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
508b5ff1b31Sbellard }
509b5ff1b31Sbellard 
510f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = {
5114b32e168Saliguori     .name = "integratorcp",
5124b32e168Saliguori     .desc = "ARM Integrator/CP (ARM926EJ-S)",
5134b32e168Saliguori     .init = integratorcp_init,
5140c257437SAnthony Liguori     .is_default = 1,
515e4ada29eSAvik Sil     DEFAULT_MACHINE_OPTIONS,
516b5ff1b31Sbellard };
517a7086888SPaul Brook 
518f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void)
519f80f9ec9SAnthony Liguori {
520f80f9ec9SAnthony Liguori     qemu_register_machine(&integratorcp_machine);
521f80f9ec9SAnthony Liguori }
522f80f9ec9SAnthony Liguori 
523f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init);
524f80f9ec9SAnthony Liguori 
525999e12bbSAnthony Liguori static Property core_properties[] = {
526bb36f66aSGerd Hoffmann     DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
527bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
528999e12bbSAnthony Liguori };
529999e12bbSAnthony Liguori 
530999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
531999e12bbSAnthony Liguori {
53239bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
533999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
534999e12bbSAnthony Liguori 
535999e12bbSAnthony Liguori     k->init = integratorcm_init;
53639bffca2SAnthony Liguori     dc->props = core_properties;
537ee6847d1SGerd Hoffmann }
538999e12bbSAnthony Liguori 
5398c43a6f0SAndreas Färber static const TypeInfo core_info = {
540999e12bbSAnthony Liguori     .name          = "integrator_core",
54139bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
54239bffca2SAnthony Liguori     .instance_size = sizeof(integratorcm_state),
543999e12bbSAnthony Liguori     .class_init    = core_class_init,
544999e12bbSAnthony Liguori };
545999e12bbSAnthony Liguori 
546999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
547999e12bbSAnthony Liguori {
548999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
549999e12bbSAnthony Liguori 
550999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
551999e12bbSAnthony Liguori }
552999e12bbSAnthony Liguori 
5538c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
554999e12bbSAnthony Liguori     .name          = "integrator_pic",
55539bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
55639bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
557999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
558ee6847d1SGerd Hoffmann };
559ee6847d1SGerd Hoffmann 
56083f7d43aSAndreas Färber static void integratorcp_register_types(void)
561a7086888SPaul Brook {
56239bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
56339bffca2SAnthony Liguori     type_register_static(&core_info);
564a7086888SPaul Brook }
565a7086888SPaul Brook 
56683f7d43aSAndreas Färber type_init(integratorcp_register_types)
567