xref: /qemu/hw/arm/integratorcp.c (revision f0d1d2c115dffc1fbaf954d0b449db05c5eb79b1) !
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 
1012b16722SPeter Maydell #include "qemu/osdep.h"
11da34e65cSMarkus Armbruster #include "qapi/error.h"
124771d756SPaolo Bonzini #include "qemu-common.h"
134771d756SPaolo Bonzini #include "cpu.h"
1483c9f4caSPaolo Bonzini #include "hw/sysbus.h"
15bd2be150SPeter Maydell #include "hw/devices.h"
1683c9f4caSPaolo Bonzini #include "hw/boards.h"
17bd2be150SPeter Maydell #include "hw/arm/arm.h"
18b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h"
191422e32dSPaolo Bonzini #include "net/net.h"
20022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
219c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
22223a72f1SGreg Bellows #include "qemu/error-report.h"
23*f0d1d2c1Sxiaoqiang zhao #include "hw/char/pl011.h"
24b5ff1b31Sbellard 
25257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
26257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
27257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
28257ec289SAndreas Färber 
29257ec289SAndreas Färber typedef struct IntegratorCMState {
30257ec289SAndreas Färber     /*< private >*/
31257ec289SAndreas Färber     SysBusDevice parent_obj;
32257ec289SAndreas Färber     /*< public >*/
33257ec289SAndreas Färber 
3471d9bc50SBenoît Canet     MemoryRegion iomem;
35ee6847d1SGerd Hoffmann     uint32_t memsz;
36211adf4dSAvi Kivity     MemoryRegion flash;
37b5ff1b31Sbellard     uint32_t cm_osc;
38b5ff1b31Sbellard     uint32_t cm_ctrl;
39b5ff1b31Sbellard     uint32_t cm_lock;
40b5ff1b31Sbellard     uint32_t cm_auxosc;
41b5ff1b31Sbellard     uint32_t cm_sdram;
42b5ff1b31Sbellard     uint32_t cm_init;
43b5ff1b31Sbellard     uint32_t cm_flags;
44b5ff1b31Sbellard     uint32_t cm_nvflags;
45f53977f7SJan Petrous     uint32_t cm_refcnt_offset;
46b5ff1b31Sbellard     uint32_t int_level;
47b5ff1b31Sbellard     uint32_t irq_enabled;
48b5ff1b31Sbellard     uint32_t fiq_enabled;
49257ec289SAndreas Färber } IntegratorCMState;
50b5ff1b31Sbellard 
51b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
52b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
53b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
54b5ff1b31Sbellard };
55b5ff1b31Sbellard 
56a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5771d9bc50SBenoît Canet                                   unsigned size)
58b5ff1b31Sbellard {
59257ec289SAndreas Färber     IntegratorCMState *s = opaque;
60b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
61b5ff1b31Sbellard         /* CM_SPD */
62b5ff1b31Sbellard         if (offset >= 0x180)
63b5ff1b31Sbellard             return 0;
64b5ff1b31Sbellard         return integrator_spd[offset >> 2];
65b5ff1b31Sbellard     }
66b5ff1b31Sbellard     switch (offset >> 2) {
67b5ff1b31Sbellard     case 0: /* CM_ID */
68b5ff1b31Sbellard         return 0x411a3001;
69b5ff1b31Sbellard     case 1: /* CM_PROC */
70b5ff1b31Sbellard         return 0;
71b5ff1b31Sbellard     case 2: /* CM_OSC */
72b5ff1b31Sbellard         return s->cm_osc;
73b5ff1b31Sbellard     case 3: /* CM_CTRL */
74b5ff1b31Sbellard         return s->cm_ctrl;
75b5ff1b31Sbellard     case 4: /* CM_STAT */
76b5ff1b31Sbellard         return 0x00100000;
77b5ff1b31Sbellard     case 5: /* CM_LOCK */
78b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
79b5ff1b31Sbellard             return 0x1a05f;
80b5ff1b31Sbellard         } else {
81b5ff1b31Sbellard             return s->cm_lock;
82b5ff1b31Sbellard         }
83b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
84b5ff1b31Sbellard         /* ??? High frequency timer.  */
852ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
86b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
87b5ff1b31Sbellard         return s->cm_auxosc;
88b5ff1b31Sbellard     case 8: /* CM_SDRAM */
89b5ff1b31Sbellard         return s->cm_sdram;
90b5ff1b31Sbellard     case 9: /* CM_INIT */
91b5ff1b31Sbellard         return s->cm_init;
92f53977f7SJan Petrous     case 10: /* CM_REFCNT */
93f53977f7SJan Petrous         /* This register, CM_REFCNT, provides a 32-bit count value.
94f53977f7SJan Petrous          * The count increments at the fixed reference clock frequency of 24MHz
95f53977f7SJan Petrous          * and can be used as a real-time counter.
96f53977f7SJan Petrous          */
97f53977f7SJan Petrous         return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
98f53977f7SJan Petrous                                   1000) - s->cm_refcnt_offset;
99b5ff1b31Sbellard     case 12: /* CM_FLAGS */
100b5ff1b31Sbellard         return s->cm_flags;
101b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
102b5ff1b31Sbellard         return s->cm_nvflags;
103b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
104b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
105b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
106b5ff1b31Sbellard         return s->int_level;
107b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
108b5ff1b31Sbellard         return s->irq_enabled;
109b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
110b5ff1b31Sbellard         return s->int_level & 1;
111b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
112b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
113b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
114b5ff1b31Sbellard         return s->int_level;
115b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
116b5ff1b31Sbellard         return s->fiq_enabled;
117b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
118b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
119b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
120b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
121b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
122b5ff1b31Sbellard         return 0;
123b5ff1b31Sbellard     default:
1242ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1252ac71179SPaul Brook                  (int)offset);
126b5ff1b31Sbellard         return 0;
127b5ff1b31Sbellard     }
128b5ff1b31Sbellard }
129b5ff1b31Sbellard 
130257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
131b5ff1b31Sbellard {
132563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
133563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
134563c2bf3SPeter Maydell      */
135563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
136b5ff1b31Sbellard }
137b5ff1b31Sbellard 
138257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
139b5ff1b31Sbellard {
140b5ff1b31Sbellard     if (value & 8) {
141df3f457bSPeter Maydell         qemu_system_reset_request();
142b5ff1b31Sbellard     }
143df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
144df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
145df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
146df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
147df3f457bSPeter Maydell          * will swamp anything else on the terminal.
148df3f457bSPeter Maydell          */
149b5ff1b31Sbellard     }
150df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
151df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
152563c2bf3SPeter Maydell     integratorcm_do_remap(s);
153b5ff1b31Sbellard }
154b5ff1b31Sbellard 
155257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
156b5ff1b31Sbellard {
157b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
158b5ff1b31Sbellard        are active.  */
159b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1602ac71179SPaul Brook         hw_error("Core module interrupt\n");
161b5ff1b31Sbellard }
162b5ff1b31Sbellard 
163a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
16471d9bc50SBenoît Canet                                uint64_t value, unsigned size)
165b5ff1b31Sbellard {
166257ec289SAndreas Färber     IntegratorCMState *s = opaque;
167b5ff1b31Sbellard     switch (offset >> 2) {
168b5ff1b31Sbellard     case 2: /* CM_OSC */
169b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
170b5ff1b31Sbellard             s->cm_osc = value;
171b5ff1b31Sbellard         break;
172b5ff1b31Sbellard     case 3: /* CM_CTRL */
173b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
174b5ff1b31Sbellard         break;
175b5ff1b31Sbellard     case 5: /* CM_LOCK */
176b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
177b5ff1b31Sbellard         break;
178b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
179b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
180b5ff1b31Sbellard             s->cm_auxosc = value;
181b5ff1b31Sbellard         break;
182b5ff1b31Sbellard     case 8: /* CM_SDRAM */
183b5ff1b31Sbellard         s->cm_sdram = value;
184b5ff1b31Sbellard         break;
185b5ff1b31Sbellard     case 9: /* CM_INIT */
186b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
187b5ff1b31Sbellard         s->cm_init = value;
188b5ff1b31Sbellard         break;
189b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
190b5ff1b31Sbellard         s->cm_flags |= value;
191b5ff1b31Sbellard         break;
192b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
193b5ff1b31Sbellard         s->cm_flags &= ~value;
194b5ff1b31Sbellard         break;
195b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
196b5ff1b31Sbellard         s->cm_nvflags |= value;
197b5ff1b31Sbellard         break;
198b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
199b5ff1b31Sbellard         s->cm_nvflags &= ~value;
200b5ff1b31Sbellard         break;
201b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
202b5ff1b31Sbellard         s->irq_enabled |= value;
203b5ff1b31Sbellard         integratorcm_update(s);
204b5ff1b31Sbellard         break;
205b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
206b5ff1b31Sbellard         s->irq_enabled &= ~value;
207b5ff1b31Sbellard         integratorcm_update(s);
208b5ff1b31Sbellard         break;
209b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
210b5ff1b31Sbellard         s->int_level |= (value & 1);
211b5ff1b31Sbellard         integratorcm_update(s);
212b5ff1b31Sbellard         break;
213b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
214b5ff1b31Sbellard         s->int_level &= ~(value & 1);
215b5ff1b31Sbellard         integratorcm_update(s);
216b5ff1b31Sbellard         break;
217b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
218b5ff1b31Sbellard         s->fiq_enabled |= value;
219b5ff1b31Sbellard         integratorcm_update(s);
220b5ff1b31Sbellard         break;
221b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
222b5ff1b31Sbellard         s->fiq_enabled &= ~value;
223b5ff1b31Sbellard         integratorcm_update(s);
224b5ff1b31Sbellard         break;
225b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
226b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
227b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
228b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
229b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
230b5ff1b31Sbellard         break;
231b5ff1b31Sbellard     default:
2322ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2332ac71179SPaul Brook                  (int)offset);
234b5ff1b31Sbellard         break;
235b5ff1b31Sbellard     }
236b5ff1b31Sbellard }
237b5ff1b31Sbellard 
238b5ff1b31Sbellard /* Integrator/CM control registers.  */
239b5ff1b31Sbellard 
24071d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
24171d9bc50SBenoît Canet     .read = integratorcm_read,
24271d9bc50SBenoît Canet     .write = integratorcm_write,
24371d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
244b5ff1b31Sbellard };
245b5ff1b31Sbellard 
246a1f42e0cSxiaoqiang.zhao static void integratorcm_init(Object *obj)
247b5ff1b31Sbellard {
248a1f42e0cSxiaoqiang.zhao     IntegratorCMState *s = INTEGRATOR_CM(obj);
249a1f42e0cSxiaoqiang.zhao     SysBusDevice *dev = SYS_BUS_DEVICE(obj);
250b5ff1b31Sbellard 
251b5ff1b31Sbellard     s->cm_osc = 0x01000048;
252b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
253b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
254b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
255ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
256b5ff1b31Sbellard         integrator_spd[31] = 64;
257b5ff1b31Sbellard         s->cm_sdram |= 0x10;
258ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
259b5ff1b31Sbellard         integrator_spd[31] = 32;
260b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
261ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
262b5ff1b31Sbellard         integrator_spd[31] = 16;
263b5ff1b31Sbellard         s->cm_sdram |= 0x08;
264ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
265b5ff1b31Sbellard         integrator_spd[31] = 4;
266b5ff1b31Sbellard         s->cm_sdram |= 0x04;
267b5ff1b31Sbellard     } else {
268b5ff1b31Sbellard         integrator_spd[31] = 2;
269b5ff1b31Sbellard     }
270b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
271b5ff1b31Sbellard     s->cm_init = 0x00000112;
272f53977f7SJan Petrous     s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
273f53977f7SJan Petrous                                    1000);
274a1f42e0cSxiaoqiang.zhao     memory_region_init_ram(&s->flash, obj, "integrator.flash", 0x100000,
275f8ed85acSMarkus Armbruster                            &error_fatal);
276c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
277b5ff1b31Sbellard 
278a1f42e0cSxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &integratorcm_ops, s,
27971d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
280750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
28171d9bc50SBenoît Canet 
282563c2bf3SPeter Maydell     integratorcm_do_remap(s);
283b5ff1b31Sbellard     /* ??? Save/restore.  */
284b5ff1b31Sbellard }
285b5ff1b31Sbellard 
286b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
287b5ff1b31Sbellard /* Primary interrupt controller.  */
288b5ff1b31Sbellard 
28991b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
29091b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
29191b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
29291b64626SAndreas Färber 
29391b64626SAndreas Färber typedef struct icp_pic_state {
29491b64626SAndreas Färber     /*< private >*/
29591b64626SAndreas Färber     SysBusDevice parent_obj;
29691b64626SAndreas Färber     /*< public >*/
29791b64626SAndreas Färber 
29861074e46SBenoît Canet     MemoryRegion iomem;
299b5ff1b31Sbellard     uint32_t level;
300b5ff1b31Sbellard     uint32_t irq_enabled;
301b5ff1b31Sbellard     uint32_t fiq_enabled;
302d537cf6cSpbrook     qemu_irq parent_irq;
303d537cf6cSpbrook     qemu_irq parent_fiq;
304b5ff1b31Sbellard } icp_pic_state;
305b5ff1b31Sbellard 
306b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
307b5ff1b31Sbellard {
308b5ff1b31Sbellard     uint32_t flags;
309b5ff1b31Sbellard 
310b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
311d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
312cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
313d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
314b5ff1b31Sbellard }
315b5ff1b31Sbellard 
316cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
317b5ff1b31Sbellard {
31880337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
319b5ff1b31Sbellard     if (level)
32080337b66Sbellard         s->level |= 1 << irq;
321b5ff1b31Sbellard     else
32280337b66Sbellard         s->level &= ~(1 << irq);
323b5ff1b31Sbellard     icp_pic_update(s);
324b5ff1b31Sbellard }
325b5ff1b31Sbellard 
326a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
32761074e46SBenoît Canet                              unsigned size)
328b5ff1b31Sbellard {
329b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
330b5ff1b31Sbellard 
331b5ff1b31Sbellard     switch (offset >> 2) {
332b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
333b5ff1b31Sbellard         return s->level & s->irq_enabled;
334b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
335b5ff1b31Sbellard         return s->level;
336b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
337b5ff1b31Sbellard         return s->irq_enabled;
338b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
339b5ff1b31Sbellard         return s->level & 1;
340b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
341b5ff1b31Sbellard         return s->level & s->fiq_enabled;
342b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
343b5ff1b31Sbellard         return s->level;
344b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
345b5ff1b31Sbellard         return s->fiq_enabled;
346b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
347b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
348b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
349b5ff1b31Sbellard     default:
35029bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
351b5ff1b31Sbellard         return 0;
352b5ff1b31Sbellard     }
353b5ff1b31Sbellard }
354b5ff1b31Sbellard 
355a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
35661074e46SBenoît Canet                           uint64_t value, unsigned size)
357b5ff1b31Sbellard {
358b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
359b5ff1b31Sbellard 
360b5ff1b31Sbellard     switch (offset >> 2) {
361b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
362b5ff1b31Sbellard         s->irq_enabled |= value;
363b5ff1b31Sbellard         break;
364b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
365b5ff1b31Sbellard         s->irq_enabled &= ~value;
366b5ff1b31Sbellard         break;
367b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
368b5ff1b31Sbellard         if (value & 1)
369d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
370b5ff1b31Sbellard         break;
371b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
372b5ff1b31Sbellard         if (value & 1)
373d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
374b5ff1b31Sbellard         break;
375b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
376b5ff1b31Sbellard         s->fiq_enabled |= value;
377b5ff1b31Sbellard         break;
378b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
379b5ff1b31Sbellard         s->fiq_enabled &= ~value;
380b5ff1b31Sbellard         break;
381b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
382b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
383b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
384b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
385b5ff1b31Sbellard     default:
38629bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
387b5ff1b31Sbellard         return;
388b5ff1b31Sbellard     }
389b5ff1b31Sbellard     icp_pic_update(s);
390b5ff1b31Sbellard }
391b5ff1b31Sbellard 
39261074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
39361074e46SBenoît Canet     .read = icp_pic_read,
39461074e46SBenoît Canet     .write = icp_pic_write,
39561074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
396b5ff1b31Sbellard };
397b5ff1b31Sbellard 
398a1f42e0cSxiaoqiang.zhao static void icp_pic_init(Object *obj)
399b5ff1b31Sbellard {
400a1f42e0cSxiaoqiang.zhao     DeviceState *dev = DEVICE(obj);
401a1f42e0cSxiaoqiang.zhao     icp_pic_state *s = INTEGRATOR_PIC(obj);
402a1f42e0cSxiaoqiang.zhao     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
403b5ff1b31Sbellard 
40491b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
40591b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
40691b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
407a1f42e0cSxiaoqiang.zhao     memory_region_init_io(&s->iomem, obj, &icp_pic_ops, s,
40864bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
40991b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
410b5ff1b31Sbellard }
411b5ff1b31Sbellard 
412b5ff1b31Sbellard /* CP control registers.  */
4130c36493eSBenoît Canet 
414ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
415ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \
416ffc8542aSJan Kiszka     OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
417ffc8542aSJan Kiszka 
418ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState {
419ffc8542aSJan Kiszka     /*< private >*/
420ffc8542aSJan Kiszka     SysBusDevice parent_obj;
421ffc8542aSJan Kiszka     /*< public >*/
422ffc8542aSJan Kiszka 
423ffc8542aSJan Kiszka     MemoryRegion iomem;
42483d0cf89SJan Kiszka 
42583d0cf89SJan Kiszka     qemu_irq mmc_irq;
42683d0cf89SJan Kiszka     uint32_t intreg_state;
427ffc8542aSJan Kiszka } ICPCtrlRegsState;
428ffc8542aSJan Kiszka 
42983d0cf89SJan Kiszka #define ICP_GPIO_MMC_WPROT      "mmc-wprot"
43083d0cf89SJan Kiszka #define ICP_GPIO_MMC_CARDIN     "mmc-cardin"
43183d0cf89SJan Kiszka 
43283d0cf89SJan Kiszka #define ICP_INTREG_WPROT        (1 << 0)
43383d0cf89SJan Kiszka #define ICP_INTREG_CARDIN       (1 << 3)
43483d0cf89SJan Kiszka 
435a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4360c36493eSBenoît Canet                                  unsigned size)
437b5ff1b31Sbellard {
43883d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
43983d0cf89SJan Kiszka 
440b5ff1b31Sbellard     switch (offset >> 2) {
441b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
442b5ff1b31Sbellard         return 0x41034003;
443b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
444b5ff1b31Sbellard         return 0;
445b5ff1b31Sbellard     case 2: /* CP_INTREG */
44683d0cf89SJan Kiszka         return s->intreg_state;
447b5ff1b31Sbellard     case 3: /* CP_DECODE */
448b5ff1b31Sbellard         return 0x11;
449b5ff1b31Sbellard     default:
4502ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
451b5ff1b31Sbellard         return 0;
452b5ff1b31Sbellard     }
453b5ff1b31Sbellard }
454b5ff1b31Sbellard 
455a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4560c36493eSBenoît Canet                           uint64_t value, unsigned size)
457b5ff1b31Sbellard {
45883d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
45983d0cf89SJan Kiszka 
460b5ff1b31Sbellard     switch (offset >> 2) {
461b5ff1b31Sbellard     case 2: /* CP_INTREG */
46283d0cf89SJan Kiszka         s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
46383d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
46483d0cf89SJan Kiszka         break;
46583d0cf89SJan Kiszka     case 1: /* CP_FLASHPROG */
466b5ff1b31Sbellard     case 3: /* CP_DECODE */
467b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
468b5ff1b31Sbellard         break;
469b5ff1b31Sbellard     default:
4702ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
471b5ff1b31Sbellard     }
472b5ff1b31Sbellard }
4730c36493eSBenoît Canet 
4740c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4750c36493eSBenoît Canet     .read = icp_control_read,
4760c36493eSBenoît Canet     .write = icp_control_write,
4770c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
478b5ff1b31Sbellard };
479b5ff1b31Sbellard 
48083d0cf89SJan Kiszka static void icp_control_mmc_wprot(void *opaque, int line, int level)
48183d0cf89SJan Kiszka {
48283d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
48383d0cf89SJan Kiszka 
48483d0cf89SJan Kiszka     s->intreg_state &= ~ICP_INTREG_WPROT;
48583d0cf89SJan Kiszka     if (level) {
48683d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_WPROT;
48783d0cf89SJan Kiszka     }
48883d0cf89SJan Kiszka }
48983d0cf89SJan Kiszka 
49083d0cf89SJan Kiszka static void icp_control_mmc_cardin(void *opaque, int line, int level)
49183d0cf89SJan Kiszka {
49283d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
49383d0cf89SJan Kiszka 
49483d0cf89SJan Kiszka     /* line is released by writing to CP_INTREG */
49583d0cf89SJan Kiszka     if (level) {
49683d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_CARDIN;
49783d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, 1);
49883d0cf89SJan Kiszka     }
49983d0cf89SJan Kiszka }
50083d0cf89SJan Kiszka 
501ffc8542aSJan Kiszka static void icp_control_init(Object *obj)
502b5ff1b31Sbellard {
503ffc8542aSJan Kiszka     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
504ffc8542aSJan Kiszka     ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
50583d0cf89SJan Kiszka     DeviceState *dev = DEVICE(obj);
506b5ff1b31Sbellard 
507ffc8542aSJan Kiszka     memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
508ffc8542aSJan Kiszka                           "icp_ctrl_regs", 0x00800000);
509ffc8542aSJan Kiszka     sysbus_init_mmio(sbd, &s->iomem);
51083d0cf89SJan Kiszka 
51183d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
51283d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
51383d0cf89SJan Kiszka                             ICP_GPIO_MMC_CARDIN, 1);
51483d0cf89SJan Kiszka     sysbus_init_irq(sbd, &s->mmc_irq);
515b5ff1b31Sbellard }
516b5ff1b31Sbellard 
517b5ff1b31Sbellard 
518b5ff1b31Sbellard /* Board init.  */
519b5ff1b31Sbellard 
520f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
521f93eb9ffSbalrog     .loader_start = 0x0,
522f93eb9ffSbalrog     .board_id = 0x113,
523f93eb9ffSbalrog };
524f93eb9ffSbalrog 
5253ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine)
526b5ff1b31Sbellard {
5273ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
5283ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
5293ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
5303ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
5313ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
532223a72f1SGreg Bellows     ObjectClass *cpu_oc;
533223a72f1SGreg Bellows     Object *cpuobj;
534393a9eabSAndreas Färber     ARMCPU *cpu;
535211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
536211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
537211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
538a7086888SPaul Brook     qemu_irq pic[32];
53983d0cf89SJan Kiszka     DeviceState *dev, *sic, *icp;
540a7086888SPaul Brook     int i;
541b5ff1b31Sbellard 
542393a9eabSAndreas Färber     if (!cpu_model) {
5433371d272Spbrook         cpu_model = "arm926";
544393a9eabSAndreas Färber     }
545223a72f1SGreg Bellows 
546223a72f1SGreg Bellows     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
547223a72f1SGreg Bellows     if (!cpu_oc) {
548aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
549aaed909aSbellard         exit(1);
550aaed909aSbellard     }
551393a9eabSAndreas Färber 
552223a72f1SGreg Bellows     cpuobj = object_new(object_class_get_name(cpu_oc));
553223a72f1SGreg Bellows 
55461e2f352SGreg Bellows     /* By default ARM1176 CPUs have EL3 enabled.  This board does not
55561e2f352SGreg Bellows      * currently support EL3 so the CPU EL3 property is disabled before
55661e2f352SGreg Bellows      * realization.
55761e2f352SGreg Bellows      */
55861e2f352SGreg Bellows     if (object_property_find(cpuobj, "has_el3", NULL)) {
559007b0657SMarkus Armbruster         object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
56061e2f352SGreg Bellows     }
56161e2f352SGreg Bellows 
562007b0657SMarkus Armbruster     object_property_set_bool(cpuobj, true, "realized", &error_fatal);
563223a72f1SGreg Bellows 
564223a72f1SGreg Bellows     cpu = ARM_CPU(cpuobj);
565223a72f1SGreg Bellows 
566c8623c02SDirk Müller     memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
567c8623c02SDirk Müller                                          ram_size);
568b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
5691235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
570b5ff1b31Sbellard     /* SDRAM at address zero*/
571211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
572b5ff1b31Sbellard     /* And again at address 0x80000000 */
5732c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
574211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
575b5ff1b31Sbellard 
576257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
577ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
578e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
579a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
580a7086888SPaul Brook 
58191b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
58299d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
58399d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
58499d228d6SPeter Maydell                                 NULL);
585a7086888SPaul Brook     for (i = 0; i < 32; i++) {
586067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
587a7086888SPaul Brook     }
58883d0cf89SJan Kiszka     sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5896a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5906a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
591a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
592*f0d1d2c1Sxiaoqiang zhao     pl011_create(0x16000000, pic[1], serial_hds[0]);
593*f0d1d2c1Sxiaoqiang zhao     pl011_create(0x17000000, pic[2], serial_hds[1]);
59483d0cf89SJan Kiszka     icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
59583d0cf89SJan Kiszka                                qdev_get_gpio_in(sic, 3));
59686394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
59786394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
598b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
59983d0cf89SJan Kiszka 
60083d0cf89SJan Kiszka     dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
60183d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 0,
60283d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
60383d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 1,
60483d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
60583d0cf89SJan Kiszka 
606a005d073SStefan Hajnoczi     if (nd_table[0].used)
607d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
6082e9bdce5SPaul Brook 
6092e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
610b5ff1b31Sbellard 
611f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
612f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
613f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
614f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
6153aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
616b5ff1b31Sbellard }
617b5ff1b31Sbellard 
618e264d29dSEduardo Habkost static void integratorcp_machine_init(MachineClass *mc)
619f80f9ec9SAnthony Liguori {
620e264d29dSEduardo Habkost     mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
621e264d29dSEduardo Habkost     mc->init = integratorcp_init;
622f80f9ec9SAnthony Liguori }
623f80f9ec9SAnthony Liguori 
624e264d29dSEduardo Habkost DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
625f80f9ec9SAnthony Liguori 
626999e12bbSAnthony Liguori static Property core_properties[] = {
627257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
628bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
629999e12bbSAnthony Liguori };
630999e12bbSAnthony Liguori 
631999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
632999e12bbSAnthony Liguori {
63339bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
634999e12bbSAnthony Liguori 
63539bffca2SAnthony Liguori     dc->props = core_properties;
636ee6847d1SGerd Hoffmann }
637999e12bbSAnthony Liguori 
6388c43a6f0SAndreas Färber static const TypeInfo core_info = {
639257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
64039bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
641257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
642a1f42e0cSxiaoqiang.zhao     .instance_init = integratorcm_init,
643999e12bbSAnthony Liguori     .class_init    = core_class_init,
644999e12bbSAnthony Liguori };
645999e12bbSAnthony Liguori 
6468c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
64791b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
64839bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
64939bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
650a1f42e0cSxiaoqiang.zhao     .instance_init = icp_pic_init,
651ee6847d1SGerd Hoffmann };
652ee6847d1SGerd Hoffmann 
653ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = {
654ffc8542aSJan Kiszka     .name          = TYPE_ICP_CONTROL_REGS,
655ffc8542aSJan Kiszka     .parent        = TYPE_SYS_BUS_DEVICE,
656ffc8542aSJan Kiszka     .instance_size = sizeof(ICPCtrlRegsState),
657ffc8542aSJan Kiszka     .instance_init = icp_control_init,
658ffc8542aSJan Kiszka };
659ffc8542aSJan Kiszka 
66083f7d43aSAndreas Färber static void integratorcp_register_types(void)
661a7086888SPaul Brook {
66239bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
66339bffca2SAnthony Liguori     type_register_static(&core_info);
664ffc8542aSJan Kiszka     type_register_static(&icp_ctrl_regs_info);
665a7086888SPaul Brook }
666a7086888SPaul Brook 
66783f7d43aSAndreas Färber type_init(integratorcp_register_types)
668