xref: /qemu/hw/arm/integratorcp.c (revision 91b646264e1c1f37c9ffb3a602ad748b2a6b050c)
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"
11bd2be150SPeter Maydell #include "hw/devices.h"
1283c9f4caSPaolo Bonzini #include "hw/boards.h"
13bd2be150SPeter 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 
18257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
19257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
20257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
21257ec289SAndreas Färber 
22257ec289SAndreas Färber typedef struct IntegratorCMState {
23257ec289SAndreas Färber     /*< private >*/
24257ec289SAndreas Färber     SysBusDevice parent_obj;
25257ec289SAndreas Färber     /*< public >*/
26257ec289SAndreas Färber 
2771d9bc50SBenoît Canet     MemoryRegion iomem;
28ee6847d1SGerd Hoffmann     uint32_t memsz;
29211adf4dSAvi Kivity     MemoryRegion flash;
30b5ff1b31Sbellard     uint32_t cm_osc;
31b5ff1b31Sbellard     uint32_t cm_ctrl;
32b5ff1b31Sbellard     uint32_t cm_lock;
33b5ff1b31Sbellard     uint32_t cm_auxosc;
34b5ff1b31Sbellard     uint32_t cm_sdram;
35b5ff1b31Sbellard     uint32_t cm_init;
36b5ff1b31Sbellard     uint32_t cm_flags;
37b5ff1b31Sbellard     uint32_t cm_nvflags;
38b5ff1b31Sbellard     uint32_t int_level;
39b5ff1b31Sbellard     uint32_t irq_enabled;
40b5ff1b31Sbellard     uint32_t fiq_enabled;
41257ec289SAndreas Färber } IntegratorCMState;
42b5ff1b31Sbellard 
43b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
44b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
45b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
46b5ff1b31Sbellard };
47b5ff1b31Sbellard 
48a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
4971d9bc50SBenoît Canet                                   unsigned size)
50b5ff1b31Sbellard {
51257ec289SAndreas Färber     IntegratorCMState *s = opaque;
52b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
53b5ff1b31Sbellard         /* CM_SPD */
54b5ff1b31Sbellard         if (offset >= 0x180)
55b5ff1b31Sbellard             return 0;
56b5ff1b31Sbellard         return integrator_spd[offset >> 2];
57b5ff1b31Sbellard     }
58b5ff1b31Sbellard     switch (offset >> 2) {
59b5ff1b31Sbellard     case 0: /* CM_ID */
60b5ff1b31Sbellard         return 0x411a3001;
61b5ff1b31Sbellard     case 1: /* CM_PROC */
62b5ff1b31Sbellard         return 0;
63b5ff1b31Sbellard     case 2: /* CM_OSC */
64b5ff1b31Sbellard         return s->cm_osc;
65b5ff1b31Sbellard     case 3: /* CM_CTRL */
66b5ff1b31Sbellard         return s->cm_ctrl;
67b5ff1b31Sbellard     case 4: /* CM_STAT */
68b5ff1b31Sbellard         return 0x00100000;
69b5ff1b31Sbellard     case 5: /* CM_LOCK */
70b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
71b5ff1b31Sbellard             return 0x1a05f;
72b5ff1b31Sbellard         } else {
73b5ff1b31Sbellard             return s->cm_lock;
74b5ff1b31Sbellard         }
75b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
76b5ff1b31Sbellard         /* ??? High frequency timer.  */
772ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
78b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
79b5ff1b31Sbellard         return s->cm_auxosc;
80b5ff1b31Sbellard     case 8: /* CM_SDRAM */
81b5ff1b31Sbellard         return s->cm_sdram;
82b5ff1b31Sbellard     case 9: /* CM_INIT */
83b5ff1b31Sbellard         return s->cm_init;
84b5ff1b31Sbellard     case 10: /* CM_REFCT */
85b5ff1b31Sbellard         /* ??? High frequency timer.  */
862ac71179SPaul Brook         hw_error("integratorcm_read: CM_REFCT");
87b5ff1b31Sbellard     case 12: /* CM_FLAGS */
88b5ff1b31Sbellard         return s->cm_flags;
89b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
90b5ff1b31Sbellard         return s->cm_nvflags;
91b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
92b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
93b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
94b5ff1b31Sbellard         return s->int_level;
95b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
96b5ff1b31Sbellard         return s->irq_enabled;
97b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
98b5ff1b31Sbellard         return s->int_level & 1;
99b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
100b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
101b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
102b5ff1b31Sbellard         return s->int_level;
103b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
104b5ff1b31Sbellard         return s->fiq_enabled;
105b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
106b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
107b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
108b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
109b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
110b5ff1b31Sbellard         return 0;
111b5ff1b31Sbellard     default:
1122ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1132ac71179SPaul Brook                  (int)offset);
114b5ff1b31Sbellard         return 0;
115b5ff1b31Sbellard     }
116b5ff1b31Sbellard }
117b5ff1b31Sbellard 
118257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
119b5ff1b31Sbellard {
120563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
121563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
122563c2bf3SPeter Maydell      */
123563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
124b5ff1b31Sbellard }
125b5ff1b31Sbellard 
126257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
127b5ff1b31Sbellard {
128b5ff1b31Sbellard     if (value & 8) {
129df3f457bSPeter Maydell         qemu_system_reset_request();
130b5ff1b31Sbellard     }
131df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
132df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
133df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
134df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
135df3f457bSPeter Maydell          * will swamp anything else on the terminal.
136df3f457bSPeter Maydell          */
137b5ff1b31Sbellard     }
138df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
139df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
140563c2bf3SPeter Maydell     integratorcm_do_remap(s);
141b5ff1b31Sbellard }
142b5ff1b31Sbellard 
143257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
144b5ff1b31Sbellard {
145b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
146b5ff1b31Sbellard        are active.  */
147b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1482ac71179SPaul Brook         hw_error("Core module interrupt\n");
149b5ff1b31Sbellard }
150b5ff1b31Sbellard 
151a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
15271d9bc50SBenoît Canet                                uint64_t value, unsigned size)
153b5ff1b31Sbellard {
154257ec289SAndreas Färber     IntegratorCMState *s = opaque;
155b5ff1b31Sbellard     switch (offset >> 2) {
156b5ff1b31Sbellard     case 2: /* CM_OSC */
157b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
158b5ff1b31Sbellard             s->cm_osc = value;
159b5ff1b31Sbellard         break;
160b5ff1b31Sbellard     case 3: /* CM_CTRL */
161b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
162b5ff1b31Sbellard         break;
163b5ff1b31Sbellard     case 5: /* CM_LOCK */
164b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
165b5ff1b31Sbellard         break;
166b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
167b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
168b5ff1b31Sbellard             s->cm_auxosc = value;
169b5ff1b31Sbellard         break;
170b5ff1b31Sbellard     case 8: /* CM_SDRAM */
171b5ff1b31Sbellard         s->cm_sdram = value;
172b5ff1b31Sbellard         break;
173b5ff1b31Sbellard     case 9: /* CM_INIT */
174b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
175b5ff1b31Sbellard         s->cm_init = value;
176b5ff1b31Sbellard         break;
177b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
178b5ff1b31Sbellard         s->cm_flags |= value;
179b5ff1b31Sbellard         break;
180b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
181b5ff1b31Sbellard         s->cm_flags &= ~value;
182b5ff1b31Sbellard         break;
183b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
184b5ff1b31Sbellard         s->cm_nvflags |= value;
185b5ff1b31Sbellard         break;
186b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
187b5ff1b31Sbellard         s->cm_nvflags &= ~value;
188b5ff1b31Sbellard         break;
189b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
190b5ff1b31Sbellard         s->irq_enabled |= value;
191b5ff1b31Sbellard         integratorcm_update(s);
192b5ff1b31Sbellard         break;
193b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
194b5ff1b31Sbellard         s->irq_enabled &= ~value;
195b5ff1b31Sbellard         integratorcm_update(s);
196b5ff1b31Sbellard         break;
197b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
198b5ff1b31Sbellard         s->int_level |= (value & 1);
199b5ff1b31Sbellard         integratorcm_update(s);
200b5ff1b31Sbellard         break;
201b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
202b5ff1b31Sbellard         s->int_level &= ~(value & 1);
203b5ff1b31Sbellard         integratorcm_update(s);
204b5ff1b31Sbellard         break;
205b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
206b5ff1b31Sbellard         s->fiq_enabled |= value;
207b5ff1b31Sbellard         integratorcm_update(s);
208b5ff1b31Sbellard         break;
209b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
210b5ff1b31Sbellard         s->fiq_enabled &= ~value;
211b5ff1b31Sbellard         integratorcm_update(s);
212b5ff1b31Sbellard         break;
213b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
214b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
215b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
216b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
217b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
218b5ff1b31Sbellard         break;
219b5ff1b31Sbellard     default:
2202ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2212ac71179SPaul Brook                  (int)offset);
222b5ff1b31Sbellard         break;
223b5ff1b31Sbellard     }
224b5ff1b31Sbellard }
225b5ff1b31Sbellard 
226b5ff1b31Sbellard /* Integrator/CM control registers.  */
227b5ff1b31Sbellard 
22871d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
22971d9bc50SBenoît Canet     .read = integratorcm_read,
23071d9bc50SBenoît Canet     .write = integratorcm_write,
23171d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
232b5ff1b31Sbellard };
233b5ff1b31Sbellard 
23481a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
235b5ff1b31Sbellard {
236257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
237b5ff1b31Sbellard 
238b5ff1b31Sbellard     s->cm_osc = 0x01000048;
239b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
240b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
241b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
242ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
243b5ff1b31Sbellard         integrator_spd[31] = 64;
244b5ff1b31Sbellard         s->cm_sdram |= 0x10;
245ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
246b5ff1b31Sbellard         integrator_spd[31] = 32;
247b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
248ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
249b5ff1b31Sbellard         integrator_spd[31] = 16;
250b5ff1b31Sbellard         s->cm_sdram |= 0x08;
251ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
252b5ff1b31Sbellard         integrator_spd[31] = 4;
253b5ff1b31Sbellard         s->cm_sdram |= 0x04;
254b5ff1b31Sbellard     } else {
255b5ff1b31Sbellard         integrator_spd[31] = 2;
256b5ff1b31Sbellard     }
257b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
258b5ff1b31Sbellard     s->cm_init = 0x00000112;
25964bde0f3SPaolo Bonzini     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000);
260c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
261b5ff1b31Sbellard 
26264bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
26371d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
264750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
26571d9bc50SBenoît Canet 
266563c2bf3SPeter Maydell     integratorcm_do_remap(s);
267b5ff1b31Sbellard     /* ??? Save/restore.  */
26881a322d4SGerd Hoffmann     return 0;
269b5ff1b31Sbellard }
270b5ff1b31Sbellard 
271b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
272b5ff1b31Sbellard /* Primary interrupt controller.  */
273b5ff1b31Sbellard 
274*91b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
275*91b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
276*91b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
277*91b64626SAndreas Färber 
278*91b64626SAndreas Färber typedef struct icp_pic_state {
279*91b64626SAndreas Färber     /*< private >*/
280*91b64626SAndreas Färber     SysBusDevice parent_obj;
281*91b64626SAndreas Färber     /*< public >*/
282*91b64626SAndreas Färber 
28361074e46SBenoît Canet     MemoryRegion iomem;
284b5ff1b31Sbellard     uint32_t level;
285b5ff1b31Sbellard     uint32_t irq_enabled;
286b5ff1b31Sbellard     uint32_t fiq_enabled;
287d537cf6cSpbrook     qemu_irq parent_irq;
288d537cf6cSpbrook     qemu_irq parent_fiq;
289b5ff1b31Sbellard } icp_pic_state;
290b5ff1b31Sbellard 
291b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
292b5ff1b31Sbellard {
293b5ff1b31Sbellard     uint32_t flags;
294b5ff1b31Sbellard 
295b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
296d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
297cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
298d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
299b5ff1b31Sbellard }
300b5ff1b31Sbellard 
301cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
302b5ff1b31Sbellard {
30380337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
304b5ff1b31Sbellard     if (level)
30580337b66Sbellard         s->level |= 1 << irq;
306b5ff1b31Sbellard     else
30780337b66Sbellard         s->level &= ~(1 << irq);
308b5ff1b31Sbellard     icp_pic_update(s);
309b5ff1b31Sbellard }
310b5ff1b31Sbellard 
311a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
31261074e46SBenoît Canet                              unsigned size)
313b5ff1b31Sbellard {
314b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
315b5ff1b31Sbellard 
316b5ff1b31Sbellard     switch (offset >> 2) {
317b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
318b5ff1b31Sbellard         return s->level & s->irq_enabled;
319b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
320b5ff1b31Sbellard         return s->level;
321b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
322b5ff1b31Sbellard         return s->irq_enabled;
323b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
324b5ff1b31Sbellard         return s->level & 1;
325b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
326b5ff1b31Sbellard         return s->level & s->fiq_enabled;
327b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
328b5ff1b31Sbellard         return s->level;
329b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
330b5ff1b31Sbellard         return s->fiq_enabled;
331b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
332b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
333b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
334b5ff1b31Sbellard     default:
33529bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
336b5ff1b31Sbellard         return 0;
337b5ff1b31Sbellard     }
338b5ff1b31Sbellard }
339b5ff1b31Sbellard 
340a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
34161074e46SBenoît Canet                           uint64_t value, unsigned size)
342b5ff1b31Sbellard {
343b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
344b5ff1b31Sbellard 
345b5ff1b31Sbellard     switch (offset >> 2) {
346b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
347b5ff1b31Sbellard         s->irq_enabled |= value;
348b5ff1b31Sbellard         break;
349b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
350b5ff1b31Sbellard         s->irq_enabled &= ~value;
351b5ff1b31Sbellard         break;
352b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
353b5ff1b31Sbellard         if (value & 1)
354d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
355b5ff1b31Sbellard         break;
356b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
357b5ff1b31Sbellard         if (value & 1)
358d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
359b5ff1b31Sbellard         break;
360b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
361b5ff1b31Sbellard         s->fiq_enabled |= value;
362b5ff1b31Sbellard         break;
363b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
364b5ff1b31Sbellard         s->fiq_enabled &= ~value;
365b5ff1b31Sbellard         break;
366b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
367b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
368b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
369b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
370b5ff1b31Sbellard     default:
37129bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
372b5ff1b31Sbellard         return;
373b5ff1b31Sbellard     }
374b5ff1b31Sbellard     icp_pic_update(s);
375b5ff1b31Sbellard }
376b5ff1b31Sbellard 
37761074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
37861074e46SBenoît Canet     .read = icp_pic_read,
37961074e46SBenoît Canet     .write = icp_pic_write,
38061074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
381b5ff1b31Sbellard };
382b5ff1b31Sbellard 
383*91b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
384b5ff1b31Sbellard {
385*91b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
386*91b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
387b5ff1b31Sbellard 
388*91b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
389*91b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
390*91b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
39164bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
39264bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
393*91b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
39481a322d4SGerd Hoffmann     return 0;
395b5ff1b31Sbellard }
396b5ff1b31Sbellard 
397b5ff1b31Sbellard /* CP control registers.  */
3980c36493eSBenoît Canet 
399a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4000c36493eSBenoît Canet                                  unsigned size)
401b5ff1b31Sbellard {
402b5ff1b31Sbellard     switch (offset >> 2) {
403b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
404b5ff1b31Sbellard         return 0x41034003;
405b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
406b5ff1b31Sbellard         return 0;
407b5ff1b31Sbellard     case 2: /* CP_INTREG */
408b5ff1b31Sbellard         return 0;
409b5ff1b31Sbellard     case 3: /* CP_DECODE */
410b5ff1b31Sbellard         return 0x11;
411b5ff1b31Sbellard     default:
4122ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
413b5ff1b31Sbellard         return 0;
414b5ff1b31Sbellard     }
415b5ff1b31Sbellard }
416b5ff1b31Sbellard 
417a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4180c36493eSBenoît Canet                           uint64_t value, unsigned size)
419b5ff1b31Sbellard {
420b5ff1b31Sbellard     switch (offset >> 2) {
421b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
422b5ff1b31Sbellard     case 2: /* CP_INTREG */
423b5ff1b31Sbellard     case 3: /* CP_DECODE */
424b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
425b5ff1b31Sbellard         break;
426b5ff1b31Sbellard     default:
4272ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
428b5ff1b31Sbellard     }
429b5ff1b31Sbellard }
4300c36493eSBenoît Canet 
4310c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4320c36493eSBenoît Canet     .read = icp_control_read,
4330c36493eSBenoît Canet     .write = icp_control_write,
4340c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
435b5ff1b31Sbellard };
436b5ff1b31Sbellard 
437a8170e5eSAvi Kivity static void icp_control_init(hwaddr base)
438b5ff1b31Sbellard {
4390c36493eSBenoît Canet     MemoryRegion *io;
440b5ff1b31Sbellard 
4410c36493eSBenoît Canet     io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
4422c9b15caSPaolo Bonzini     memory_region_init_io(io, NULL, &icp_control_ops, NULL,
4430c36493eSBenoît Canet                           "control", 0x00800000);
4440c36493eSBenoît Canet     memory_region_add_subregion(get_system_memory(), base, io);
445b5ff1b31Sbellard     /* ??? Save/restore.  */
446b5ff1b31Sbellard }
447b5ff1b31Sbellard 
448b5ff1b31Sbellard 
449b5ff1b31Sbellard /* Board init.  */
450b5ff1b31Sbellard 
451f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
452f93eb9ffSbalrog     .loader_start = 0x0,
453f93eb9ffSbalrog     .board_id = 0x113,
454f93eb9ffSbalrog };
455f93eb9ffSbalrog 
4565f072e1fSEduardo Habkost static void integratorcp_init(QEMUMachineInitArgs *args)
457b5ff1b31Sbellard {
4585f072e1fSEduardo Habkost     ram_addr_t ram_size = args->ram_size;
4595f072e1fSEduardo Habkost     const char *cpu_model = args->cpu_model;
4605f072e1fSEduardo Habkost     const char *kernel_filename = args->kernel_filename;
4615f072e1fSEduardo Habkost     const char *kernel_cmdline = args->kernel_cmdline;
4625f072e1fSEduardo Habkost     const char *initrd_filename = args->initrd_filename;
463393a9eabSAndreas Färber     ARMCPU *cpu;
464211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
465211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
466211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
467a7086888SPaul Brook     qemu_irq pic[32];
468d537cf6cSpbrook     qemu_irq *cpu_pic;
469a7086888SPaul Brook     DeviceState *dev;
470a7086888SPaul Brook     int i;
471b5ff1b31Sbellard 
472393a9eabSAndreas Färber     if (!cpu_model) {
4733371d272Spbrook         cpu_model = "arm926";
474393a9eabSAndreas Färber     }
475393a9eabSAndreas Färber     cpu = cpu_arm_init(cpu_model);
476393a9eabSAndreas Färber     if (!cpu) {
477aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
478aaed909aSbellard         exit(1);
479aaed909aSbellard     }
480393a9eabSAndreas Färber 
4812c9b15caSPaolo Bonzini     memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
482c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
483b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
4841235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
485b5ff1b31Sbellard     /* SDRAM at address zero*/
486211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
487b5ff1b31Sbellard     /* And again at address 0x80000000 */
4882c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
489211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
490b5ff1b31Sbellard 
491257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
492ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
493e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
494a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
495a7086888SPaul Brook 
4964bd74661SAndreas Färber     cpu_pic = arm_pic_init_cpu(cpu);
497*91b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
498a7086888SPaul Brook                                 cpu_pic[ARM_PIC_CPU_IRQ],
499a7086888SPaul Brook                                 cpu_pic[ARM_PIC_CPU_FIQ], NULL);
500a7086888SPaul Brook     for (i = 0; i < 32; i++) {
501067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
502a7086888SPaul Brook     }
503*91b64626SAndreas Färber     sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5046a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5056a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
506a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
507a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
508a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
509b5ff1b31Sbellard     icp_control_init(0xcb000000);
51086394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
51186394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
512aa9311d8SPaul Brook     sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
513a005d073SStefan Hajnoczi     if (nd_table[0].used)
514d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
5152e9bdce5SPaul Brook 
5162e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
517b5ff1b31Sbellard 
518f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
519f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
520f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
521f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
5223aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
523b5ff1b31Sbellard }
524b5ff1b31Sbellard 
525f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = {
5264b32e168Saliguori     .name = "integratorcp",
5274b32e168Saliguori     .desc = "ARM Integrator/CP (ARM926EJ-S)",
5284b32e168Saliguori     .init = integratorcp_init,
5290c257437SAnthony Liguori     .is_default = 1,
530e4ada29eSAvik Sil     DEFAULT_MACHINE_OPTIONS,
531b5ff1b31Sbellard };
532a7086888SPaul Brook 
533f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void)
534f80f9ec9SAnthony Liguori {
535f80f9ec9SAnthony Liguori     qemu_register_machine(&integratorcp_machine);
536f80f9ec9SAnthony Liguori }
537f80f9ec9SAnthony Liguori 
538f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init);
539f80f9ec9SAnthony Liguori 
540999e12bbSAnthony Liguori static Property core_properties[] = {
541257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
542bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
543999e12bbSAnthony Liguori };
544999e12bbSAnthony Liguori 
545999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
546999e12bbSAnthony Liguori {
54739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
548999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
549999e12bbSAnthony Liguori 
550999e12bbSAnthony Liguori     k->init = integratorcm_init;
55139bffca2SAnthony Liguori     dc->props = core_properties;
552ee6847d1SGerd Hoffmann }
553999e12bbSAnthony Liguori 
5548c43a6f0SAndreas Färber static const TypeInfo core_info = {
555257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
55639bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
557257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
558999e12bbSAnthony Liguori     .class_init    = core_class_init,
559999e12bbSAnthony Liguori };
560999e12bbSAnthony Liguori 
561999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
562999e12bbSAnthony Liguori {
563999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
564999e12bbSAnthony Liguori 
565999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
566999e12bbSAnthony Liguori }
567999e12bbSAnthony Liguori 
5688c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
569*91b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
57039bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
57139bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
572999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
573ee6847d1SGerd Hoffmann };
574ee6847d1SGerd Hoffmann 
57583f7d43aSAndreas Färber static void integratorcp_register_types(void)
576a7086888SPaul Brook {
57739bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
57839bffca2SAnthony Liguori     type_register_static(&core_info);
579a7086888SPaul Brook }
580a7086888SPaul Brook 
58183f7d43aSAndreas Färber type_init(integratorcp_register_types)
582