xref: /qemu/hw/arm/integratorcp.c (revision 49946538d29618319a54e798f22bbcc8065ad106)
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"
14b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h"
151422e32dSPaolo Bonzini #include "net/net.h"
16022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
179c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
18b5ff1b31Sbellard 
19257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
20257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
21257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
22257ec289SAndreas Färber 
23257ec289SAndreas Färber typedef struct IntegratorCMState {
24257ec289SAndreas Färber     /*< private >*/
25257ec289SAndreas Färber     SysBusDevice parent_obj;
26257ec289SAndreas Färber     /*< public >*/
27257ec289SAndreas Färber 
2871d9bc50SBenoît Canet     MemoryRegion iomem;
29ee6847d1SGerd Hoffmann     uint32_t memsz;
30211adf4dSAvi Kivity     MemoryRegion flash;
31b5ff1b31Sbellard     uint32_t cm_osc;
32b5ff1b31Sbellard     uint32_t cm_ctrl;
33b5ff1b31Sbellard     uint32_t cm_lock;
34b5ff1b31Sbellard     uint32_t cm_auxosc;
35b5ff1b31Sbellard     uint32_t cm_sdram;
36b5ff1b31Sbellard     uint32_t cm_init;
37b5ff1b31Sbellard     uint32_t cm_flags;
38b5ff1b31Sbellard     uint32_t cm_nvflags;
39f53977f7SJan Petrous     uint32_t cm_refcnt_offset;
40b5ff1b31Sbellard     uint32_t int_level;
41b5ff1b31Sbellard     uint32_t irq_enabled;
42b5ff1b31Sbellard     uint32_t fiq_enabled;
43257ec289SAndreas Färber } IntegratorCMState;
44b5ff1b31Sbellard 
45b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
46b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
47b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
48b5ff1b31Sbellard };
49b5ff1b31Sbellard 
50a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5171d9bc50SBenoît Canet                                   unsigned size)
52b5ff1b31Sbellard {
53257ec289SAndreas Färber     IntegratorCMState *s = opaque;
54b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
55b5ff1b31Sbellard         /* CM_SPD */
56b5ff1b31Sbellard         if (offset >= 0x180)
57b5ff1b31Sbellard             return 0;
58b5ff1b31Sbellard         return integrator_spd[offset >> 2];
59b5ff1b31Sbellard     }
60b5ff1b31Sbellard     switch (offset >> 2) {
61b5ff1b31Sbellard     case 0: /* CM_ID */
62b5ff1b31Sbellard         return 0x411a3001;
63b5ff1b31Sbellard     case 1: /* CM_PROC */
64b5ff1b31Sbellard         return 0;
65b5ff1b31Sbellard     case 2: /* CM_OSC */
66b5ff1b31Sbellard         return s->cm_osc;
67b5ff1b31Sbellard     case 3: /* CM_CTRL */
68b5ff1b31Sbellard         return s->cm_ctrl;
69b5ff1b31Sbellard     case 4: /* CM_STAT */
70b5ff1b31Sbellard         return 0x00100000;
71b5ff1b31Sbellard     case 5: /* CM_LOCK */
72b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
73b5ff1b31Sbellard             return 0x1a05f;
74b5ff1b31Sbellard         } else {
75b5ff1b31Sbellard             return s->cm_lock;
76b5ff1b31Sbellard         }
77b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
78b5ff1b31Sbellard         /* ??? High frequency timer.  */
792ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
80b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
81b5ff1b31Sbellard         return s->cm_auxosc;
82b5ff1b31Sbellard     case 8: /* CM_SDRAM */
83b5ff1b31Sbellard         return s->cm_sdram;
84b5ff1b31Sbellard     case 9: /* CM_INIT */
85b5ff1b31Sbellard         return s->cm_init;
86f53977f7SJan Petrous     case 10: /* CM_REFCNT */
87f53977f7SJan Petrous         /* This register, CM_REFCNT, provides a 32-bit count value.
88f53977f7SJan Petrous          * The count increments at the fixed reference clock frequency of 24MHz
89f53977f7SJan Petrous          * and can be used as a real-time counter.
90f53977f7SJan Petrous          */
91f53977f7SJan Petrous         return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
92f53977f7SJan Petrous                                   1000) - s->cm_refcnt_offset;
93b5ff1b31Sbellard     case 12: /* CM_FLAGS */
94b5ff1b31Sbellard         return s->cm_flags;
95b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
96b5ff1b31Sbellard         return s->cm_nvflags;
97b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
98b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
99b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
100b5ff1b31Sbellard         return s->int_level;
101b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
102b5ff1b31Sbellard         return s->irq_enabled;
103b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
104b5ff1b31Sbellard         return s->int_level & 1;
105b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
106b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
107b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
108b5ff1b31Sbellard         return s->int_level;
109b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
110b5ff1b31Sbellard         return s->fiq_enabled;
111b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
112b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
113b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
114b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
115b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
116b5ff1b31Sbellard         return 0;
117b5ff1b31Sbellard     default:
1182ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1192ac71179SPaul Brook                  (int)offset);
120b5ff1b31Sbellard         return 0;
121b5ff1b31Sbellard     }
122b5ff1b31Sbellard }
123b5ff1b31Sbellard 
124257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
125b5ff1b31Sbellard {
126563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
127563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
128563c2bf3SPeter Maydell      */
129563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
130b5ff1b31Sbellard }
131b5ff1b31Sbellard 
132257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
133b5ff1b31Sbellard {
134b5ff1b31Sbellard     if (value & 8) {
135df3f457bSPeter Maydell         qemu_system_reset_request();
136b5ff1b31Sbellard     }
137df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
138df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
139df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
140df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
141df3f457bSPeter Maydell          * will swamp anything else on the terminal.
142df3f457bSPeter Maydell          */
143b5ff1b31Sbellard     }
144df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
145df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
146563c2bf3SPeter Maydell     integratorcm_do_remap(s);
147b5ff1b31Sbellard }
148b5ff1b31Sbellard 
149257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
150b5ff1b31Sbellard {
151b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
152b5ff1b31Sbellard        are active.  */
153b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1542ac71179SPaul Brook         hw_error("Core module interrupt\n");
155b5ff1b31Sbellard }
156b5ff1b31Sbellard 
157a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
15871d9bc50SBenoît Canet                                uint64_t value, unsigned size)
159b5ff1b31Sbellard {
160257ec289SAndreas Färber     IntegratorCMState *s = opaque;
161b5ff1b31Sbellard     switch (offset >> 2) {
162b5ff1b31Sbellard     case 2: /* CM_OSC */
163b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
164b5ff1b31Sbellard             s->cm_osc = value;
165b5ff1b31Sbellard         break;
166b5ff1b31Sbellard     case 3: /* CM_CTRL */
167b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
168b5ff1b31Sbellard         break;
169b5ff1b31Sbellard     case 5: /* CM_LOCK */
170b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
171b5ff1b31Sbellard         break;
172b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
173b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
174b5ff1b31Sbellard             s->cm_auxosc = value;
175b5ff1b31Sbellard         break;
176b5ff1b31Sbellard     case 8: /* CM_SDRAM */
177b5ff1b31Sbellard         s->cm_sdram = value;
178b5ff1b31Sbellard         break;
179b5ff1b31Sbellard     case 9: /* CM_INIT */
180b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
181b5ff1b31Sbellard         s->cm_init = value;
182b5ff1b31Sbellard         break;
183b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
184b5ff1b31Sbellard         s->cm_flags |= value;
185b5ff1b31Sbellard         break;
186b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
187b5ff1b31Sbellard         s->cm_flags &= ~value;
188b5ff1b31Sbellard         break;
189b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
190b5ff1b31Sbellard         s->cm_nvflags |= value;
191b5ff1b31Sbellard         break;
192b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
193b5ff1b31Sbellard         s->cm_nvflags &= ~value;
194b5ff1b31Sbellard         break;
195b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
196b5ff1b31Sbellard         s->irq_enabled |= value;
197b5ff1b31Sbellard         integratorcm_update(s);
198b5ff1b31Sbellard         break;
199b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
200b5ff1b31Sbellard         s->irq_enabled &= ~value;
201b5ff1b31Sbellard         integratorcm_update(s);
202b5ff1b31Sbellard         break;
203b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
204b5ff1b31Sbellard         s->int_level |= (value & 1);
205b5ff1b31Sbellard         integratorcm_update(s);
206b5ff1b31Sbellard         break;
207b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
208b5ff1b31Sbellard         s->int_level &= ~(value & 1);
209b5ff1b31Sbellard         integratorcm_update(s);
210b5ff1b31Sbellard         break;
211b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
212b5ff1b31Sbellard         s->fiq_enabled |= value;
213b5ff1b31Sbellard         integratorcm_update(s);
214b5ff1b31Sbellard         break;
215b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
216b5ff1b31Sbellard         s->fiq_enabled &= ~value;
217b5ff1b31Sbellard         integratorcm_update(s);
218b5ff1b31Sbellard         break;
219b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
220b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
221b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
222b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
223b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
224b5ff1b31Sbellard         break;
225b5ff1b31Sbellard     default:
2262ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2272ac71179SPaul Brook                  (int)offset);
228b5ff1b31Sbellard         break;
229b5ff1b31Sbellard     }
230b5ff1b31Sbellard }
231b5ff1b31Sbellard 
232b5ff1b31Sbellard /* Integrator/CM control registers.  */
233b5ff1b31Sbellard 
23471d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
23571d9bc50SBenoît Canet     .read = integratorcm_read,
23671d9bc50SBenoît Canet     .write = integratorcm_write,
23771d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
238b5ff1b31Sbellard };
239b5ff1b31Sbellard 
24081a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
241b5ff1b31Sbellard {
242257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
243b5ff1b31Sbellard 
244b5ff1b31Sbellard     s->cm_osc = 0x01000048;
245b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
246b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
247b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
248ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
249b5ff1b31Sbellard         integrator_spd[31] = 64;
250b5ff1b31Sbellard         s->cm_sdram |= 0x10;
251ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
252b5ff1b31Sbellard         integrator_spd[31] = 32;
253b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
254ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
255b5ff1b31Sbellard         integrator_spd[31] = 16;
256b5ff1b31Sbellard         s->cm_sdram |= 0x08;
257ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
258b5ff1b31Sbellard         integrator_spd[31] = 4;
259b5ff1b31Sbellard         s->cm_sdram |= 0x04;
260b5ff1b31Sbellard     } else {
261b5ff1b31Sbellard         integrator_spd[31] = 2;
262b5ff1b31Sbellard     }
263b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
264b5ff1b31Sbellard     s->cm_init = 0x00000112;
265f53977f7SJan Petrous     s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
266f53977f7SJan Petrous                                    1000);
267*49946538SHu Tao     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
268*49946538SHu Tao                            &error_abort);
269c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
270b5ff1b31Sbellard 
27164bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
27271d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
273750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
27471d9bc50SBenoît Canet 
275563c2bf3SPeter Maydell     integratorcm_do_remap(s);
276b5ff1b31Sbellard     /* ??? Save/restore.  */
27781a322d4SGerd Hoffmann     return 0;
278b5ff1b31Sbellard }
279b5ff1b31Sbellard 
280b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
281b5ff1b31Sbellard /* Primary interrupt controller.  */
282b5ff1b31Sbellard 
28391b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
28491b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
28591b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
28691b64626SAndreas Färber 
28791b64626SAndreas Färber typedef struct icp_pic_state {
28891b64626SAndreas Färber     /*< private >*/
28991b64626SAndreas Färber     SysBusDevice parent_obj;
29091b64626SAndreas Färber     /*< public >*/
29191b64626SAndreas Färber 
29261074e46SBenoît Canet     MemoryRegion iomem;
293b5ff1b31Sbellard     uint32_t level;
294b5ff1b31Sbellard     uint32_t irq_enabled;
295b5ff1b31Sbellard     uint32_t fiq_enabled;
296d537cf6cSpbrook     qemu_irq parent_irq;
297d537cf6cSpbrook     qemu_irq parent_fiq;
298b5ff1b31Sbellard } icp_pic_state;
299b5ff1b31Sbellard 
300b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
301b5ff1b31Sbellard {
302b5ff1b31Sbellard     uint32_t flags;
303b5ff1b31Sbellard 
304b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
305d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
306cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
307d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
308b5ff1b31Sbellard }
309b5ff1b31Sbellard 
310cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
311b5ff1b31Sbellard {
31280337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
313b5ff1b31Sbellard     if (level)
31480337b66Sbellard         s->level |= 1 << irq;
315b5ff1b31Sbellard     else
31680337b66Sbellard         s->level &= ~(1 << irq);
317b5ff1b31Sbellard     icp_pic_update(s);
318b5ff1b31Sbellard }
319b5ff1b31Sbellard 
320a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
32161074e46SBenoît Canet                              unsigned size)
322b5ff1b31Sbellard {
323b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
324b5ff1b31Sbellard 
325b5ff1b31Sbellard     switch (offset >> 2) {
326b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
327b5ff1b31Sbellard         return s->level & s->irq_enabled;
328b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
329b5ff1b31Sbellard         return s->level;
330b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
331b5ff1b31Sbellard         return s->irq_enabled;
332b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
333b5ff1b31Sbellard         return s->level & 1;
334b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
335b5ff1b31Sbellard         return s->level & s->fiq_enabled;
336b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
337b5ff1b31Sbellard         return s->level;
338b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
339b5ff1b31Sbellard         return s->fiq_enabled;
340b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
341b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
342b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
343b5ff1b31Sbellard     default:
34429bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
345b5ff1b31Sbellard         return 0;
346b5ff1b31Sbellard     }
347b5ff1b31Sbellard }
348b5ff1b31Sbellard 
349a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
35061074e46SBenoît Canet                           uint64_t value, unsigned size)
351b5ff1b31Sbellard {
352b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
353b5ff1b31Sbellard 
354b5ff1b31Sbellard     switch (offset >> 2) {
355b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
356b5ff1b31Sbellard         s->irq_enabled |= value;
357b5ff1b31Sbellard         break;
358b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
359b5ff1b31Sbellard         s->irq_enabled &= ~value;
360b5ff1b31Sbellard         break;
361b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
362b5ff1b31Sbellard         if (value & 1)
363d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
364b5ff1b31Sbellard         break;
365b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
366b5ff1b31Sbellard         if (value & 1)
367d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
368b5ff1b31Sbellard         break;
369b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
370b5ff1b31Sbellard         s->fiq_enabled |= value;
371b5ff1b31Sbellard         break;
372b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
373b5ff1b31Sbellard         s->fiq_enabled &= ~value;
374b5ff1b31Sbellard         break;
375b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
376b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
377b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
378b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
379b5ff1b31Sbellard     default:
38029bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
381b5ff1b31Sbellard         return;
382b5ff1b31Sbellard     }
383b5ff1b31Sbellard     icp_pic_update(s);
384b5ff1b31Sbellard }
385b5ff1b31Sbellard 
38661074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
38761074e46SBenoît Canet     .read = icp_pic_read,
38861074e46SBenoît Canet     .write = icp_pic_write,
38961074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
390b5ff1b31Sbellard };
391b5ff1b31Sbellard 
39291b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
393b5ff1b31Sbellard {
39491b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
39591b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
396b5ff1b31Sbellard 
39791b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
39891b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
39991b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
40064bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
40164bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
40291b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
40381a322d4SGerd Hoffmann     return 0;
404b5ff1b31Sbellard }
405b5ff1b31Sbellard 
406b5ff1b31Sbellard /* CP control registers.  */
4070c36493eSBenoît Canet 
408a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4090c36493eSBenoît Canet                                  unsigned size)
410b5ff1b31Sbellard {
411b5ff1b31Sbellard     switch (offset >> 2) {
412b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
413b5ff1b31Sbellard         return 0x41034003;
414b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
415b5ff1b31Sbellard         return 0;
416b5ff1b31Sbellard     case 2: /* CP_INTREG */
417b5ff1b31Sbellard         return 0;
418b5ff1b31Sbellard     case 3: /* CP_DECODE */
419b5ff1b31Sbellard         return 0x11;
420b5ff1b31Sbellard     default:
4212ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
422b5ff1b31Sbellard         return 0;
423b5ff1b31Sbellard     }
424b5ff1b31Sbellard }
425b5ff1b31Sbellard 
426a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4270c36493eSBenoît Canet                           uint64_t value, unsigned size)
428b5ff1b31Sbellard {
429b5ff1b31Sbellard     switch (offset >> 2) {
430b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
431b5ff1b31Sbellard     case 2: /* CP_INTREG */
432b5ff1b31Sbellard     case 3: /* CP_DECODE */
433b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
434b5ff1b31Sbellard         break;
435b5ff1b31Sbellard     default:
4362ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
437b5ff1b31Sbellard     }
438b5ff1b31Sbellard }
4390c36493eSBenoît Canet 
4400c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4410c36493eSBenoît Canet     .read = icp_control_read,
4420c36493eSBenoît Canet     .write = icp_control_write,
4430c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
444b5ff1b31Sbellard };
445b5ff1b31Sbellard 
446a8170e5eSAvi Kivity static void icp_control_init(hwaddr base)
447b5ff1b31Sbellard {
4480c36493eSBenoît Canet     MemoryRegion *io;
449b5ff1b31Sbellard 
4500c36493eSBenoît Canet     io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
4512c9b15caSPaolo Bonzini     memory_region_init_io(io, NULL, &icp_control_ops, NULL,
4520c36493eSBenoît Canet                           "control", 0x00800000);
4530c36493eSBenoît Canet     memory_region_add_subregion(get_system_memory(), base, io);
454b5ff1b31Sbellard     /* ??? Save/restore.  */
455b5ff1b31Sbellard }
456b5ff1b31Sbellard 
457b5ff1b31Sbellard 
458b5ff1b31Sbellard /* Board init.  */
459b5ff1b31Sbellard 
460f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
461f93eb9ffSbalrog     .loader_start = 0x0,
462f93eb9ffSbalrog     .board_id = 0x113,
463f93eb9ffSbalrog };
464f93eb9ffSbalrog 
4653ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine)
466b5ff1b31Sbellard {
4673ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
4683ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
4693ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
4703ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
4713ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
472393a9eabSAndreas Färber     ARMCPU *cpu;
473211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
474211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
475211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
476a7086888SPaul Brook     qemu_irq pic[32];
477a7086888SPaul Brook     DeviceState *dev;
478a7086888SPaul Brook     int i;
479b5ff1b31Sbellard 
480393a9eabSAndreas Färber     if (!cpu_model) {
4813371d272Spbrook         cpu_model = "arm926";
482393a9eabSAndreas Färber     }
483393a9eabSAndreas Färber     cpu = cpu_arm_init(cpu_model);
484393a9eabSAndreas Färber     if (!cpu) {
485aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
486aaed909aSbellard         exit(1);
487aaed909aSbellard     }
488393a9eabSAndreas Färber 
489*49946538SHu Tao     memory_region_init_ram(ram, NULL, "integrator.ram", ram_size, &error_abort);
490c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
491b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
4921235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
493b5ff1b31Sbellard     /* SDRAM at address zero*/
494211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
495b5ff1b31Sbellard     /* And again at address 0x80000000 */
4962c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
497211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
498b5ff1b31Sbellard 
499257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
500ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
501e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
502a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
503a7086888SPaul Brook 
50491b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
50599d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
50699d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
50799d228d6SPeter Maydell                                 NULL);
508a7086888SPaul Brook     for (i = 0; i < 32; i++) {
509067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
510a7086888SPaul Brook     }
51191b64626SAndreas Färber     sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5126a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5136a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
514a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
515a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
516a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
517b5ff1b31Sbellard     icp_control_init(0xcb000000);
51886394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
51986394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
520b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
521aa9311d8SPaul Brook     sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
522a005d073SStefan Hajnoczi     if (nd_table[0].used)
523d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
5242e9bdce5SPaul Brook 
5252e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
526b5ff1b31Sbellard 
527f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
528f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
529f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
530f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
5313aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
532b5ff1b31Sbellard }
533b5ff1b31Sbellard 
534f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = {
5354b32e168Saliguori     .name = "integratorcp",
5364b32e168Saliguori     .desc = "ARM Integrator/CP (ARM926EJ-S)",
5374b32e168Saliguori     .init = integratorcp_init,
538b5ff1b31Sbellard };
539a7086888SPaul Brook 
540f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void)
541f80f9ec9SAnthony Liguori {
542f80f9ec9SAnthony Liguori     qemu_register_machine(&integratorcp_machine);
543f80f9ec9SAnthony Liguori }
544f80f9ec9SAnthony Liguori 
545f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init);
546f80f9ec9SAnthony Liguori 
547999e12bbSAnthony Liguori static Property core_properties[] = {
548257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
549bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
550999e12bbSAnthony Liguori };
551999e12bbSAnthony Liguori 
552999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
553999e12bbSAnthony Liguori {
55439bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
555999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
556999e12bbSAnthony Liguori 
557999e12bbSAnthony Liguori     k->init = integratorcm_init;
55839bffca2SAnthony Liguori     dc->props = core_properties;
559ee6847d1SGerd Hoffmann }
560999e12bbSAnthony Liguori 
5618c43a6f0SAndreas Färber static const TypeInfo core_info = {
562257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
56339bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
564257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
565999e12bbSAnthony Liguori     .class_init    = core_class_init,
566999e12bbSAnthony Liguori };
567999e12bbSAnthony Liguori 
568999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
569999e12bbSAnthony Liguori {
570999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
571999e12bbSAnthony Liguori 
572999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
573999e12bbSAnthony Liguori }
574999e12bbSAnthony Liguori 
5758c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
57691b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
57739bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
57839bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
579999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
580ee6847d1SGerd Hoffmann };
581ee6847d1SGerd Hoffmann 
58283f7d43aSAndreas Färber static void integratorcp_register_types(void)
583a7086888SPaul Brook {
58439bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
58539bffca2SAnthony Liguori     type_register_static(&core_info);
586a7086888SPaul Brook }
587a7086888SPaul Brook 
58883f7d43aSAndreas Färber type_init(integratorcp_register_types)
589