xref: /qemu/hw/arm/integratorcp.c (revision c8623c0215e18eb4a8ec73eba014d97e51ed707e)
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"
18223a72f1SGreg Bellows #include "qemu/error-report.h"
19b5ff1b31Sbellard 
20257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
21257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
22257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
23257ec289SAndreas Färber 
24257ec289SAndreas Färber typedef struct IntegratorCMState {
25257ec289SAndreas Färber     /*< private >*/
26257ec289SAndreas Färber     SysBusDevice parent_obj;
27257ec289SAndreas Färber     /*< public >*/
28257ec289SAndreas Färber 
2971d9bc50SBenoît Canet     MemoryRegion iomem;
30ee6847d1SGerd Hoffmann     uint32_t memsz;
31211adf4dSAvi Kivity     MemoryRegion flash;
32b5ff1b31Sbellard     uint32_t cm_osc;
33b5ff1b31Sbellard     uint32_t cm_ctrl;
34b5ff1b31Sbellard     uint32_t cm_lock;
35b5ff1b31Sbellard     uint32_t cm_auxosc;
36b5ff1b31Sbellard     uint32_t cm_sdram;
37b5ff1b31Sbellard     uint32_t cm_init;
38b5ff1b31Sbellard     uint32_t cm_flags;
39b5ff1b31Sbellard     uint32_t cm_nvflags;
40f53977f7SJan Petrous     uint32_t cm_refcnt_offset;
41b5ff1b31Sbellard     uint32_t int_level;
42b5ff1b31Sbellard     uint32_t irq_enabled;
43b5ff1b31Sbellard     uint32_t fiq_enabled;
44257ec289SAndreas Färber } IntegratorCMState;
45b5ff1b31Sbellard 
46b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
47b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
48b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
49b5ff1b31Sbellard };
50b5ff1b31Sbellard 
51a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5271d9bc50SBenoît Canet                                   unsigned size)
53b5ff1b31Sbellard {
54257ec289SAndreas Färber     IntegratorCMState *s = opaque;
55b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
56b5ff1b31Sbellard         /* CM_SPD */
57b5ff1b31Sbellard         if (offset >= 0x180)
58b5ff1b31Sbellard             return 0;
59b5ff1b31Sbellard         return integrator_spd[offset >> 2];
60b5ff1b31Sbellard     }
61b5ff1b31Sbellard     switch (offset >> 2) {
62b5ff1b31Sbellard     case 0: /* CM_ID */
63b5ff1b31Sbellard         return 0x411a3001;
64b5ff1b31Sbellard     case 1: /* CM_PROC */
65b5ff1b31Sbellard         return 0;
66b5ff1b31Sbellard     case 2: /* CM_OSC */
67b5ff1b31Sbellard         return s->cm_osc;
68b5ff1b31Sbellard     case 3: /* CM_CTRL */
69b5ff1b31Sbellard         return s->cm_ctrl;
70b5ff1b31Sbellard     case 4: /* CM_STAT */
71b5ff1b31Sbellard         return 0x00100000;
72b5ff1b31Sbellard     case 5: /* CM_LOCK */
73b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
74b5ff1b31Sbellard             return 0x1a05f;
75b5ff1b31Sbellard         } else {
76b5ff1b31Sbellard             return s->cm_lock;
77b5ff1b31Sbellard         }
78b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
79b5ff1b31Sbellard         /* ??? High frequency timer.  */
802ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
81b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
82b5ff1b31Sbellard         return s->cm_auxosc;
83b5ff1b31Sbellard     case 8: /* CM_SDRAM */
84b5ff1b31Sbellard         return s->cm_sdram;
85b5ff1b31Sbellard     case 9: /* CM_INIT */
86b5ff1b31Sbellard         return s->cm_init;
87f53977f7SJan Petrous     case 10: /* CM_REFCNT */
88f53977f7SJan Petrous         /* This register, CM_REFCNT, provides a 32-bit count value.
89f53977f7SJan Petrous          * The count increments at the fixed reference clock frequency of 24MHz
90f53977f7SJan Petrous          * and can be used as a real-time counter.
91f53977f7SJan Petrous          */
92f53977f7SJan Petrous         return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
93f53977f7SJan Petrous                                   1000) - s->cm_refcnt_offset;
94b5ff1b31Sbellard     case 12: /* CM_FLAGS */
95b5ff1b31Sbellard         return s->cm_flags;
96b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
97b5ff1b31Sbellard         return s->cm_nvflags;
98b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
99b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
100b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
101b5ff1b31Sbellard         return s->int_level;
102b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
103b5ff1b31Sbellard         return s->irq_enabled;
104b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
105b5ff1b31Sbellard         return s->int_level & 1;
106b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
107b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
108b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
109b5ff1b31Sbellard         return s->int_level;
110b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
111b5ff1b31Sbellard         return s->fiq_enabled;
112b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
113b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
114b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
115b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
116b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
117b5ff1b31Sbellard         return 0;
118b5ff1b31Sbellard     default:
1192ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1202ac71179SPaul Brook                  (int)offset);
121b5ff1b31Sbellard         return 0;
122b5ff1b31Sbellard     }
123b5ff1b31Sbellard }
124b5ff1b31Sbellard 
125257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
126b5ff1b31Sbellard {
127563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
128563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
129563c2bf3SPeter Maydell      */
130563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
131b5ff1b31Sbellard }
132b5ff1b31Sbellard 
133257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
134b5ff1b31Sbellard {
135b5ff1b31Sbellard     if (value & 8) {
136df3f457bSPeter Maydell         qemu_system_reset_request();
137b5ff1b31Sbellard     }
138df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
139df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
140df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
141df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
142df3f457bSPeter Maydell          * will swamp anything else on the terminal.
143df3f457bSPeter Maydell          */
144b5ff1b31Sbellard     }
145df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
146df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
147563c2bf3SPeter Maydell     integratorcm_do_remap(s);
148b5ff1b31Sbellard }
149b5ff1b31Sbellard 
150257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
151b5ff1b31Sbellard {
152b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
153b5ff1b31Sbellard        are active.  */
154b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1552ac71179SPaul Brook         hw_error("Core module interrupt\n");
156b5ff1b31Sbellard }
157b5ff1b31Sbellard 
158a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
15971d9bc50SBenoît Canet                                uint64_t value, unsigned size)
160b5ff1b31Sbellard {
161257ec289SAndreas Färber     IntegratorCMState *s = opaque;
162b5ff1b31Sbellard     switch (offset >> 2) {
163b5ff1b31Sbellard     case 2: /* CM_OSC */
164b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
165b5ff1b31Sbellard             s->cm_osc = value;
166b5ff1b31Sbellard         break;
167b5ff1b31Sbellard     case 3: /* CM_CTRL */
168b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
169b5ff1b31Sbellard         break;
170b5ff1b31Sbellard     case 5: /* CM_LOCK */
171b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
172b5ff1b31Sbellard         break;
173b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
174b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
175b5ff1b31Sbellard             s->cm_auxosc = value;
176b5ff1b31Sbellard         break;
177b5ff1b31Sbellard     case 8: /* CM_SDRAM */
178b5ff1b31Sbellard         s->cm_sdram = value;
179b5ff1b31Sbellard         break;
180b5ff1b31Sbellard     case 9: /* CM_INIT */
181b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
182b5ff1b31Sbellard         s->cm_init = value;
183b5ff1b31Sbellard         break;
184b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
185b5ff1b31Sbellard         s->cm_flags |= value;
186b5ff1b31Sbellard         break;
187b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
188b5ff1b31Sbellard         s->cm_flags &= ~value;
189b5ff1b31Sbellard         break;
190b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
191b5ff1b31Sbellard         s->cm_nvflags |= value;
192b5ff1b31Sbellard         break;
193b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
194b5ff1b31Sbellard         s->cm_nvflags &= ~value;
195b5ff1b31Sbellard         break;
196b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
197b5ff1b31Sbellard         s->irq_enabled |= value;
198b5ff1b31Sbellard         integratorcm_update(s);
199b5ff1b31Sbellard         break;
200b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
201b5ff1b31Sbellard         s->irq_enabled &= ~value;
202b5ff1b31Sbellard         integratorcm_update(s);
203b5ff1b31Sbellard         break;
204b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
205b5ff1b31Sbellard         s->int_level |= (value & 1);
206b5ff1b31Sbellard         integratorcm_update(s);
207b5ff1b31Sbellard         break;
208b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
209b5ff1b31Sbellard         s->int_level &= ~(value & 1);
210b5ff1b31Sbellard         integratorcm_update(s);
211b5ff1b31Sbellard         break;
212b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
213b5ff1b31Sbellard         s->fiq_enabled |= value;
214b5ff1b31Sbellard         integratorcm_update(s);
215b5ff1b31Sbellard         break;
216b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
217b5ff1b31Sbellard         s->fiq_enabled &= ~value;
218b5ff1b31Sbellard         integratorcm_update(s);
219b5ff1b31Sbellard         break;
220b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
221b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
222b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
223b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
224b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
225b5ff1b31Sbellard         break;
226b5ff1b31Sbellard     default:
2272ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2282ac71179SPaul Brook                  (int)offset);
229b5ff1b31Sbellard         break;
230b5ff1b31Sbellard     }
231b5ff1b31Sbellard }
232b5ff1b31Sbellard 
233b5ff1b31Sbellard /* Integrator/CM control registers.  */
234b5ff1b31Sbellard 
23571d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
23671d9bc50SBenoît Canet     .read = integratorcm_read,
23771d9bc50SBenoît Canet     .write = integratorcm_write,
23871d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
239b5ff1b31Sbellard };
240b5ff1b31Sbellard 
24181a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
242b5ff1b31Sbellard {
243257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
244b5ff1b31Sbellard 
245b5ff1b31Sbellard     s->cm_osc = 0x01000048;
246b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
247b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
248b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
249ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
250b5ff1b31Sbellard         integrator_spd[31] = 64;
251b5ff1b31Sbellard         s->cm_sdram |= 0x10;
252ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
253b5ff1b31Sbellard         integrator_spd[31] = 32;
254b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
255ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
256b5ff1b31Sbellard         integrator_spd[31] = 16;
257b5ff1b31Sbellard         s->cm_sdram |= 0x08;
258ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
259b5ff1b31Sbellard         integrator_spd[31] = 4;
260b5ff1b31Sbellard         s->cm_sdram |= 0x04;
261b5ff1b31Sbellard     } else {
262b5ff1b31Sbellard         integrator_spd[31] = 2;
263b5ff1b31Sbellard     }
264b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
265b5ff1b31Sbellard     s->cm_init = 0x00000112;
266f53977f7SJan Petrous     s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
267f53977f7SJan Petrous                                    1000);
26849946538SHu Tao     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
26949946538SHu Tao                            &error_abort);
270c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
271b5ff1b31Sbellard 
27264bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
27371d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
274750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
27571d9bc50SBenoît Canet 
276563c2bf3SPeter Maydell     integratorcm_do_remap(s);
277b5ff1b31Sbellard     /* ??? Save/restore.  */
27881a322d4SGerd Hoffmann     return 0;
279b5ff1b31Sbellard }
280b5ff1b31Sbellard 
281b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
282b5ff1b31Sbellard /* Primary interrupt controller.  */
283b5ff1b31Sbellard 
28491b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
28591b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
28691b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
28791b64626SAndreas Färber 
28891b64626SAndreas Färber typedef struct icp_pic_state {
28991b64626SAndreas Färber     /*< private >*/
29091b64626SAndreas Färber     SysBusDevice parent_obj;
29191b64626SAndreas Färber     /*< public >*/
29291b64626SAndreas Färber 
29361074e46SBenoît Canet     MemoryRegion iomem;
294b5ff1b31Sbellard     uint32_t level;
295b5ff1b31Sbellard     uint32_t irq_enabled;
296b5ff1b31Sbellard     uint32_t fiq_enabled;
297d537cf6cSpbrook     qemu_irq parent_irq;
298d537cf6cSpbrook     qemu_irq parent_fiq;
299b5ff1b31Sbellard } icp_pic_state;
300b5ff1b31Sbellard 
301b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
302b5ff1b31Sbellard {
303b5ff1b31Sbellard     uint32_t flags;
304b5ff1b31Sbellard 
305b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
306d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
307cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
308d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
309b5ff1b31Sbellard }
310b5ff1b31Sbellard 
311cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
312b5ff1b31Sbellard {
31380337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
314b5ff1b31Sbellard     if (level)
31580337b66Sbellard         s->level |= 1 << irq;
316b5ff1b31Sbellard     else
31780337b66Sbellard         s->level &= ~(1 << irq);
318b5ff1b31Sbellard     icp_pic_update(s);
319b5ff1b31Sbellard }
320b5ff1b31Sbellard 
321a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
32261074e46SBenoît Canet                              unsigned size)
323b5ff1b31Sbellard {
324b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
325b5ff1b31Sbellard 
326b5ff1b31Sbellard     switch (offset >> 2) {
327b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
328b5ff1b31Sbellard         return s->level & s->irq_enabled;
329b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
330b5ff1b31Sbellard         return s->level;
331b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
332b5ff1b31Sbellard         return s->irq_enabled;
333b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
334b5ff1b31Sbellard         return s->level & 1;
335b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
336b5ff1b31Sbellard         return s->level & s->fiq_enabled;
337b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
338b5ff1b31Sbellard         return s->level;
339b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
340b5ff1b31Sbellard         return s->fiq_enabled;
341b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
342b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
343b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
344b5ff1b31Sbellard     default:
34529bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
346b5ff1b31Sbellard         return 0;
347b5ff1b31Sbellard     }
348b5ff1b31Sbellard }
349b5ff1b31Sbellard 
350a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
35161074e46SBenoît Canet                           uint64_t value, unsigned size)
352b5ff1b31Sbellard {
353b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
354b5ff1b31Sbellard 
355b5ff1b31Sbellard     switch (offset >> 2) {
356b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
357b5ff1b31Sbellard         s->irq_enabled |= value;
358b5ff1b31Sbellard         break;
359b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
360b5ff1b31Sbellard         s->irq_enabled &= ~value;
361b5ff1b31Sbellard         break;
362b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
363b5ff1b31Sbellard         if (value & 1)
364d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
365b5ff1b31Sbellard         break;
366b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
367b5ff1b31Sbellard         if (value & 1)
368d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
369b5ff1b31Sbellard         break;
370b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
371b5ff1b31Sbellard         s->fiq_enabled |= value;
372b5ff1b31Sbellard         break;
373b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
374b5ff1b31Sbellard         s->fiq_enabled &= ~value;
375b5ff1b31Sbellard         break;
376b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
377b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
378b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
379b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
380b5ff1b31Sbellard     default:
38129bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
382b5ff1b31Sbellard         return;
383b5ff1b31Sbellard     }
384b5ff1b31Sbellard     icp_pic_update(s);
385b5ff1b31Sbellard }
386b5ff1b31Sbellard 
38761074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
38861074e46SBenoît Canet     .read = icp_pic_read,
38961074e46SBenoît Canet     .write = icp_pic_write,
39061074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
391b5ff1b31Sbellard };
392b5ff1b31Sbellard 
39391b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
394b5ff1b31Sbellard {
39591b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
39691b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
397b5ff1b31Sbellard 
39891b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
39991b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
40091b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
40164bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
40264bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
40391b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
40481a322d4SGerd Hoffmann     return 0;
405b5ff1b31Sbellard }
406b5ff1b31Sbellard 
407b5ff1b31Sbellard /* CP control registers.  */
4080c36493eSBenoît Canet 
409ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
410ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \
411ffc8542aSJan Kiszka     OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
412ffc8542aSJan Kiszka 
413ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState {
414ffc8542aSJan Kiszka     /*< private >*/
415ffc8542aSJan Kiszka     SysBusDevice parent_obj;
416ffc8542aSJan Kiszka     /*< public >*/
417ffc8542aSJan Kiszka 
418ffc8542aSJan Kiszka     MemoryRegion iomem;
41983d0cf89SJan Kiszka 
42083d0cf89SJan Kiszka     qemu_irq mmc_irq;
42183d0cf89SJan Kiszka     uint32_t intreg_state;
422ffc8542aSJan Kiszka } ICPCtrlRegsState;
423ffc8542aSJan Kiszka 
42483d0cf89SJan Kiszka #define ICP_GPIO_MMC_WPROT      "mmc-wprot"
42583d0cf89SJan Kiszka #define ICP_GPIO_MMC_CARDIN     "mmc-cardin"
42683d0cf89SJan Kiszka 
42783d0cf89SJan Kiszka #define ICP_INTREG_WPROT        (1 << 0)
42883d0cf89SJan Kiszka #define ICP_INTREG_CARDIN       (1 << 3)
42983d0cf89SJan Kiszka 
430a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4310c36493eSBenoît Canet                                  unsigned size)
432b5ff1b31Sbellard {
43383d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
43483d0cf89SJan Kiszka 
435b5ff1b31Sbellard     switch (offset >> 2) {
436b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
437b5ff1b31Sbellard         return 0x41034003;
438b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
439b5ff1b31Sbellard         return 0;
440b5ff1b31Sbellard     case 2: /* CP_INTREG */
44183d0cf89SJan Kiszka         return s->intreg_state;
442b5ff1b31Sbellard     case 3: /* CP_DECODE */
443b5ff1b31Sbellard         return 0x11;
444b5ff1b31Sbellard     default:
4452ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
446b5ff1b31Sbellard         return 0;
447b5ff1b31Sbellard     }
448b5ff1b31Sbellard }
449b5ff1b31Sbellard 
450a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4510c36493eSBenoît Canet                           uint64_t value, unsigned size)
452b5ff1b31Sbellard {
45383d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
45483d0cf89SJan Kiszka 
455b5ff1b31Sbellard     switch (offset >> 2) {
456b5ff1b31Sbellard     case 2: /* CP_INTREG */
45783d0cf89SJan Kiszka         s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
45883d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
45983d0cf89SJan Kiszka         break;
46083d0cf89SJan Kiszka     case 1: /* CP_FLASHPROG */
461b5ff1b31Sbellard     case 3: /* CP_DECODE */
462b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
463b5ff1b31Sbellard         break;
464b5ff1b31Sbellard     default:
4652ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
466b5ff1b31Sbellard     }
467b5ff1b31Sbellard }
4680c36493eSBenoît Canet 
4690c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4700c36493eSBenoît Canet     .read = icp_control_read,
4710c36493eSBenoît Canet     .write = icp_control_write,
4720c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
473b5ff1b31Sbellard };
474b5ff1b31Sbellard 
47583d0cf89SJan Kiszka static void icp_control_mmc_wprot(void *opaque, int line, int level)
47683d0cf89SJan Kiszka {
47783d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
47883d0cf89SJan Kiszka 
47983d0cf89SJan Kiszka     s->intreg_state &= ~ICP_INTREG_WPROT;
48083d0cf89SJan Kiszka     if (level) {
48183d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_WPROT;
48283d0cf89SJan Kiszka     }
48383d0cf89SJan Kiszka }
48483d0cf89SJan Kiszka 
48583d0cf89SJan Kiszka static void icp_control_mmc_cardin(void *opaque, int line, int level)
48683d0cf89SJan Kiszka {
48783d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
48883d0cf89SJan Kiszka 
48983d0cf89SJan Kiszka     /* line is released by writing to CP_INTREG */
49083d0cf89SJan Kiszka     if (level) {
49183d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_CARDIN;
49283d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, 1);
49383d0cf89SJan Kiszka     }
49483d0cf89SJan Kiszka }
49583d0cf89SJan Kiszka 
496ffc8542aSJan Kiszka static void icp_control_init(Object *obj)
497b5ff1b31Sbellard {
498ffc8542aSJan Kiszka     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
499ffc8542aSJan Kiszka     ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
50083d0cf89SJan Kiszka     DeviceState *dev = DEVICE(obj);
501b5ff1b31Sbellard 
502ffc8542aSJan Kiszka     memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
503ffc8542aSJan Kiszka                           "icp_ctrl_regs", 0x00800000);
504ffc8542aSJan Kiszka     sysbus_init_mmio(sbd, &s->iomem);
50583d0cf89SJan Kiszka 
50683d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
50783d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
50883d0cf89SJan Kiszka                             ICP_GPIO_MMC_CARDIN, 1);
50983d0cf89SJan Kiszka     sysbus_init_irq(sbd, &s->mmc_irq);
510b5ff1b31Sbellard }
511b5ff1b31Sbellard 
512b5ff1b31Sbellard 
513b5ff1b31Sbellard /* Board init.  */
514b5ff1b31Sbellard 
515f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
516f93eb9ffSbalrog     .loader_start = 0x0,
517f93eb9ffSbalrog     .board_id = 0x113,
518f93eb9ffSbalrog };
519f93eb9ffSbalrog 
5203ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine)
521b5ff1b31Sbellard {
5223ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
5233ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
5243ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
5253ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
5263ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
527223a72f1SGreg Bellows     ObjectClass *cpu_oc;
528223a72f1SGreg Bellows     Object *cpuobj;
529393a9eabSAndreas Färber     ARMCPU *cpu;
530211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
531211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
532211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
533a7086888SPaul Brook     qemu_irq pic[32];
53483d0cf89SJan Kiszka     DeviceState *dev, *sic, *icp;
535a7086888SPaul Brook     int i;
536223a72f1SGreg Bellows     Error *err = NULL;
537b5ff1b31Sbellard 
538393a9eabSAndreas Färber     if (!cpu_model) {
5393371d272Spbrook         cpu_model = "arm926";
540393a9eabSAndreas Färber     }
541223a72f1SGreg Bellows 
542223a72f1SGreg Bellows     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
543223a72f1SGreg Bellows     if (!cpu_oc) {
544aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
545aaed909aSbellard         exit(1);
546aaed909aSbellard     }
547393a9eabSAndreas Färber 
548223a72f1SGreg Bellows     cpuobj = object_new(object_class_get_name(cpu_oc));
549223a72f1SGreg Bellows 
55061e2f352SGreg Bellows     /* By default ARM1176 CPUs have EL3 enabled.  This board does not
55161e2f352SGreg Bellows      * currently support EL3 so the CPU EL3 property is disabled before
55261e2f352SGreg Bellows      * realization.
55361e2f352SGreg Bellows      */
55461e2f352SGreg Bellows     if (object_property_find(cpuobj, "has_el3", NULL)) {
55561e2f352SGreg Bellows         object_property_set_bool(cpuobj, false, "has_el3", &err);
55661e2f352SGreg Bellows         if (err) {
557565f65d2SMarkus Armbruster             error_report_err(err);
55861e2f352SGreg Bellows             exit(1);
55961e2f352SGreg Bellows         }
56061e2f352SGreg Bellows     }
56161e2f352SGreg Bellows 
562223a72f1SGreg Bellows     object_property_set_bool(cpuobj, true, "realized", &err);
563223a72f1SGreg Bellows     if (err) {
564565f65d2SMarkus Armbruster         error_report_err(err);
565223a72f1SGreg Bellows         exit(1);
566223a72f1SGreg Bellows     }
567223a72f1SGreg Bellows 
568223a72f1SGreg Bellows     cpu = ARM_CPU(cpuobj);
569223a72f1SGreg Bellows 
570*c8623c02SDirk Müller     memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
571*c8623c02SDirk Müller                                          ram_size);
572b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
5731235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
574b5ff1b31Sbellard     /* SDRAM at address zero*/
575211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
576b5ff1b31Sbellard     /* And again at address 0x80000000 */
5772c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
578211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
579b5ff1b31Sbellard 
580257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
581ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
582e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
583a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
584a7086888SPaul Brook 
58591b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
58699d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
58799d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
58899d228d6SPeter Maydell                                 NULL);
589a7086888SPaul Brook     for (i = 0; i < 32; i++) {
590067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
591a7086888SPaul Brook     }
59283d0cf89SJan Kiszka     sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5936a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5946a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
595a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
596a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
597a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
59883d0cf89SJan Kiszka     icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
59983d0cf89SJan Kiszka                                qdev_get_gpio_in(sic, 3));
60086394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
60186394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
602b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
60383d0cf89SJan Kiszka 
60483d0cf89SJan Kiszka     dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
60583d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 0,
60683d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
60783d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 1,
60883d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
60983d0cf89SJan Kiszka 
610a005d073SStefan Hajnoczi     if (nd_table[0].used)
611d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
6122e9bdce5SPaul Brook 
6132e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
614b5ff1b31Sbellard 
615f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
616f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
617f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
618f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
6193aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
620b5ff1b31Sbellard }
621b5ff1b31Sbellard 
622f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = {
6234b32e168Saliguori     .name = "integratorcp",
6244b32e168Saliguori     .desc = "ARM Integrator/CP (ARM926EJ-S)",
6254b32e168Saliguori     .init = integratorcp_init,
626b5ff1b31Sbellard };
627a7086888SPaul Brook 
628f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void)
629f80f9ec9SAnthony Liguori {
630f80f9ec9SAnthony Liguori     qemu_register_machine(&integratorcp_machine);
631f80f9ec9SAnthony Liguori }
632f80f9ec9SAnthony Liguori 
633f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init);
634f80f9ec9SAnthony Liguori 
635999e12bbSAnthony Liguori static Property core_properties[] = {
636257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
637bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
638999e12bbSAnthony Liguori };
639999e12bbSAnthony Liguori 
640999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
641999e12bbSAnthony Liguori {
64239bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
643999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
644999e12bbSAnthony Liguori 
645999e12bbSAnthony Liguori     k->init = integratorcm_init;
64639bffca2SAnthony Liguori     dc->props = core_properties;
647ee6847d1SGerd Hoffmann }
648999e12bbSAnthony Liguori 
6498c43a6f0SAndreas Färber static const TypeInfo core_info = {
650257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
65139bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
652257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
653999e12bbSAnthony Liguori     .class_init    = core_class_init,
654999e12bbSAnthony Liguori };
655999e12bbSAnthony Liguori 
656999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
657999e12bbSAnthony Liguori {
658999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
659999e12bbSAnthony Liguori 
660999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
661999e12bbSAnthony Liguori }
662999e12bbSAnthony Liguori 
6638c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
66491b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
66539bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
66639bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
667999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
668ee6847d1SGerd Hoffmann };
669ee6847d1SGerd Hoffmann 
670ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = {
671ffc8542aSJan Kiszka     .name          = TYPE_ICP_CONTROL_REGS,
672ffc8542aSJan Kiszka     .parent        = TYPE_SYS_BUS_DEVICE,
673ffc8542aSJan Kiszka     .instance_size = sizeof(ICPCtrlRegsState),
674ffc8542aSJan Kiszka     .instance_init = icp_control_init,
675ffc8542aSJan Kiszka };
676ffc8542aSJan Kiszka 
67783f7d43aSAndreas Färber static void integratorcp_register_types(void)
678a7086888SPaul Brook {
67939bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
68039bffca2SAnthony Liguori     type_register_static(&core_info);
681ffc8542aSJan Kiszka     type_register_static(&icp_ctrl_regs_info);
682a7086888SPaul Brook }
683a7086888SPaul Brook 
68483f7d43aSAndreas Färber type_init(integratorcp_register_types)
685