xref: /qemu/hw/arm/integratorcp.c (revision 12b167226f2804063cf8d72fe4fdc01764c99e96)
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 
10*12b16722SPeter Maydell #include "qemu/osdep.h"
1183c9f4caSPaolo Bonzini #include "hw/sysbus.h"
12bd2be150SPeter Maydell #include "hw/devices.h"
1383c9f4caSPaolo Bonzini #include "hw/boards.h"
14bd2be150SPeter Maydell #include "hw/arm/arm.h"
15b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h"
161422e32dSPaolo Bonzini #include "net/net.h"
17022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
189c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
19223a72f1SGreg Bellows #include "qemu/error-report.h"
20b5ff1b31Sbellard 
21257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
22257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
23257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
24257ec289SAndreas Färber 
25257ec289SAndreas Färber typedef struct IntegratorCMState {
26257ec289SAndreas Färber     /*< private >*/
27257ec289SAndreas Färber     SysBusDevice parent_obj;
28257ec289SAndreas Färber     /*< public >*/
29257ec289SAndreas Färber 
3071d9bc50SBenoît Canet     MemoryRegion iomem;
31ee6847d1SGerd Hoffmann     uint32_t memsz;
32211adf4dSAvi Kivity     MemoryRegion flash;
33b5ff1b31Sbellard     uint32_t cm_osc;
34b5ff1b31Sbellard     uint32_t cm_ctrl;
35b5ff1b31Sbellard     uint32_t cm_lock;
36b5ff1b31Sbellard     uint32_t cm_auxosc;
37b5ff1b31Sbellard     uint32_t cm_sdram;
38b5ff1b31Sbellard     uint32_t cm_init;
39b5ff1b31Sbellard     uint32_t cm_flags;
40b5ff1b31Sbellard     uint32_t cm_nvflags;
41f53977f7SJan Petrous     uint32_t cm_refcnt_offset;
42b5ff1b31Sbellard     uint32_t int_level;
43b5ff1b31Sbellard     uint32_t irq_enabled;
44b5ff1b31Sbellard     uint32_t fiq_enabled;
45257ec289SAndreas Färber } IntegratorCMState;
46b5ff1b31Sbellard 
47b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
48b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
49b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
50b5ff1b31Sbellard };
51b5ff1b31Sbellard 
52a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5371d9bc50SBenoît Canet                                   unsigned size)
54b5ff1b31Sbellard {
55257ec289SAndreas Färber     IntegratorCMState *s = opaque;
56b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
57b5ff1b31Sbellard         /* CM_SPD */
58b5ff1b31Sbellard         if (offset >= 0x180)
59b5ff1b31Sbellard             return 0;
60b5ff1b31Sbellard         return integrator_spd[offset >> 2];
61b5ff1b31Sbellard     }
62b5ff1b31Sbellard     switch (offset >> 2) {
63b5ff1b31Sbellard     case 0: /* CM_ID */
64b5ff1b31Sbellard         return 0x411a3001;
65b5ff1b31Sbellard     case 1: /* CM_PROC */
66b5ff1b31Sbellard         return 0;
67b5ff1b31Sbellard     case 2: /* CM_OSC */
68b5ff1b31Sbellard         return s->cm_osc;
69b5ff1b31Sbellard     case 3: /* CM_CTRL */
70b5ff1b31Sbellard         return s->cm_ctrl;
71b5ff1b31Sbellard     case 4: /* CM_STAT */
72b5ff1b31Sbellard         return 0x00100000;
73b5ff1b31Sbellard     case 5: /* CM_LOCK */
74b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
75b5ff1b31Sbellard             return 0x1a05f;
76b5ff1b31Sbellard         } else {
77b5ff1b31Sbellard             return s->cm_lock;
78b5ff1b31Sbellard         }
79b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
80b5ff1b31Sbellard         /* ??? High frequency timer.  */
812ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
82b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
83b5ff1b31Sbellard         return s->cm_auxosc;
84b5ff1b31Sbellard     case 8: /* CM_SDRAM */
85b5ff1b31Sbellard         return s->cm_sdram;
86b5ff1b31Sbellard     case 9: /* CM_INIT */
87b5ff1b31Sbellard         return s->cm_init;
88f53977f7SJan Petrous     case 10: /* CM_REFCNT */
89f53977f7SJan Petrous         /* This register, CM_REFCNT, provides a 32-bit count value.
90f53977f7SJan Petrous          * The count increments at the fixed reference clock frequency of 24MHz
91f53977f7SJan Petrous          * and can be used as a real-time counter.
92f53977f7SJan Petrous          */
93f53977f7SJan Petrous         return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
94f53977f7SJan Petrous                                   1000) - s->cm_refcnt_offset;
95b5ff1b31Sbellard     case 12: /* CM_FLAGS */
96b5ff1b31Sbellard         return s->cm_flags;
97b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
98b5ff1b31Sbellard         return s->cm_nvflags;
99b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
100b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
101b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
102b5ff1b31Sbellard         return s->int_level;
103b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
104b5ff1b31Sbellard         return s->irq_enabled;
105b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
106b5ff1b31Sbellard         return s->int_level & 1;
107b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
108b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
109b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
110b5ff1b31Sbellard         return s->int_level;
111b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
112b5ff1b31Sbellard         return s->fiq_enabled;
113b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
114b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
115b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
116b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
117b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
118b5ff1b31Sbellard         return 0;
119b5ff1b31Sbellard     default:
1202ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1212ac71179SPaul Brook                  (int)offset);
122b5ff1b31Sbellard         return 0;
123b5ff1b31Sbellard     }
124b5ff1b31Sbellard }
125b5ff1b31Sbellard 
126257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
127b5ff1b31Sbellard {
128563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
129563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
130563c2bf3SPeter Maydell      */
131563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
132b5ff1b31Sbellard }
133b5ff1b31Sbellard 
134257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
135b5ff1b31Sbellard {
136b5ff1b31Sbellard     if (value & 8) {
137df3f457bSPeter Maydell         qemu_system_reset_request();
138b5ff1b31Sbellard     }
139df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
140df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
141df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
142df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
143df3f457bSPeter Maydell          * will swamp anything else on the terminal.
144df3f457bSPeter Maydell          */
145b5ff1b31Sbellard     }
146df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
147df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
148563c2bf3SPeter Maydell     integratorcm_do_remap(s);
149b5ff1b31Sbellard }
150b5ff1b31Sbellard 
151257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
152b5ff1b31Sbellard {
153b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
154b5ff1b31Sbellard        are active.  */
155b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1562ac71179SPaul Brook         hw_error("Core module interrupt\n");
157b5ff1b31Sbellard }
158b5ff1b31Sbellard 
159a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
16071d9bc50SBenoît Canet                                uint64_t value, unsigned size)
161b5ff1b31Sbellard {
162257ec289SAndreas Färber     IntegratorCMState *s = opaque;
163b5ff1b31Sbellard     switch (offset >> 2) {
164b5ff1b31Sbellard     case 2: /* CM_OSC */
165b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
166b5ff1b31Sbellard             s->cm_osc = value;
167b5ff1b31Sbellard         break;
168b5ff1b31Sbellard     case 3: /* CM_CTRL */
169b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
170b5ff1b31Sbellard         break;
171b5ff1b31Sbellard     case 5: /* CM_LOCK */
172b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
173b5ff1b31Sbellard         break;
174b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
175b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
176b5ff1b31Sbellard             s->cm_auxosc = value;
177b5ff1b31Sbellard         break;
178b5ff1b31Sbellard     case 8: /* CM_SDRAM */
179b5ff1b31Sbellard         s->cm_sdram = value;
180b5ff1b31Sbellard         break;
181b5ff1b31Sbellard     case 9: /* CM_INIT */
182b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
183b5ff1b31Sbellard         s->cm_init = value;
184b5ff1b31Sbellard         break;
185b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
186b5ff1b31Sbellard         s->cm_flags |= value;
187b5ff1b31Sbellard         break;
188b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
189b5ff1b31Sbellard         s->cm_flags &= ~value;
190b5ff1b31Sbellard         break;
191b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
192b5ff1b31Sbellard         s->cm_nvflags |= value;
193b5ff1b31Sbellard         break;
194b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
195b5ff1b31Sbellard         s->cm_nvflags &= ~value;
196b5ff1b31Sbellard         break;
197b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
198b5ff1b31Sbellard         s->irq_enabled |= value;
199b5ff1b31Sbellard         integratorcm_update(s);
200b5ff1b31Sbellard         break;
201b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
202b5ff1b31Sbellard         s->irq_enabled &= ~value;
203b5ff1b31Sbellard         integratorcm_update(s);
204b5ff1b31Sbellard         break;
205b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
206b5ff1b31Sbellard         s->int_level |= (value & 1);
207b5ff1b31Sbellard         integratorcm_update(s);
208b5ff1b31Sbellard         break;
209b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
210b5ff1b31Sbellard         s->int_level &= ~(value & 1);
211b5ff1b31Sbellard         integratorcm_update(s);
212b5ff1b31Sbellard         break;
213b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
214b5ff1b31Sbellard         s->fiq_enabled |= value;
215b5ff1b31Sbellard         integratorcm_update(s);
216b5ff1b31Sbellard         break;
217b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
218b5ff1b31Sbellard         s->fiq_enabled &= ~value;
219b5ff1b31Sbellard         integratorcm_update(s);
220b5ff1b31Sbellard         break;
221b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
222b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
223b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
224b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
225b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
226b5ff1b31Sbellard         break;
227b5ff1b31Sbellard     default:
2282ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2292ac71179SPaul Brook                  (int)offset);
230b5ff1b31Sbellard         break;
231b5ff1b31Sbellard     }
232b5ff1b31Sbellard }
233b5ff1b31Sbellard 
234b5ff1b31Sbellard /* Integrator/CM control registers.  */
235b5ff1b31Sbellard 
23671d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
23771d9bc50SBenoît Canet     .read = integratorcm_read,
23871d9bc50SBenoît Canet     .write = integratorcm_write,
23971d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
240b5ff1b31Sbellard };
241b5ff1b31Sbellard 
24281a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
243b5ff1b31Sbellard {
244257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
245b5ff1b31Sbellard 
246b5ff1b31Sbellard     s->cm_osc = 0x01000048;
247b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
248b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
249b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
250ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
251b5ff1b31Sbellard         integrator_spd[31] = 64;
252b5ff1b31Sbellard         s->cm_sdram |= 0x10;
253ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
254b5ff1b31Sbellard         integrator_spd[31] = 32;
255b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
256ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
257b5ff1b31Sbellard         integrator_spd[31] = 16;
258b5ff1b31Sbellard         s->cm_sdram |= 0x08;
259ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
260b5ff1b31Sbellard         integrator_spd[31] = 4;
261b5ff1b31Sbellard         s->cm_sdram |= 0x04;
262b5ff1b31Sbellard     } else {
263b5ff1b31Sbellard         integrator_spd[31] = 2;
264b5ff1b31Sbellard     }
265b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
266b5ff1b31Sbellard     s->cm_init = 0x00000112;
267f53977f7SJan Petrous     s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
268f53977f7SJan Petrous                                    1000);
26949946538SHu Tao     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
270f8ed85acSMarkus Armbruster                            &error_fatal);
271c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
272b5ff1b31Sbellard 
27364bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
27471d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
275750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
27671d9bc50SBenoît Canet 
277563c2bf3SPeter Maydell     integratorcm_do_remap(s);
278b5ff1b31Sbellard     /* ??? Save/restore.  */
27981a322d4SGerd Hoffmann     return 0;
280b5ff1b31Sbellard }
281b5ff1b31Sbellard 
282b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
283b5ff1b31Sbellard /* Primary interrupt controller.  */
284b5ff1b31Sbellard 
28591b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
28691b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
28791b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
28891b64626SAndreas Färber 
28991b64626SAndreas Färber typedef struct icp_pic_state {
29091b64626SAndreas Färber     /*< private >*/
29191b64626SAndreas Färber     SysBusDevice parent_obj;
29291b64626SAndreas Färber     /*< public >*/
29391b64626SAndreas Färber 
29461074e46SBenoît Canet     MemoryRegion iomem;
295b5ff1b31Sbellard     uint32_t level;
296b5ff1b31Sbellard     uint32_t irq_enabled;
297b5ff1b31Sbellard     uint32_t fiq_enabled;
298d537cf6cSpbrook     qemu_irq parent_irq;
299d537cf6cSpbrook     qemu_irq parent_fiq;
300b5ff1b31Sbellard } icp_pic_state;
301b5ff1b31Sbellard 
302b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
303b5ff1b31Sbellard {
304b5ff1b31Sbellard     uint32_t flags;
305b5ff1b31Sbellard 
306b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
307d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
308cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
309d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
310b5ff1b31Sbellard }
311b5ff1b31Sbellard 
312cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
313b5ff1b31Sbellard {
31480337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
315b5ff1b31Sbellard     if (level)
31680337b66Sbellard         s->level |= 1 << irq;
317b5ff1b31Sbellard     else
31880337b66Sbellard         s->level &= ~(1 << irq);
319b5ff1b31Sbellard     icp_pic_update(s);
320b5ff1b31Sbellard }
321b5ff1b31Sbellard 
322a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
32361074e46SBenoît Canet                              unsigned size)
324b5ff1b31Sbellard {
325b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
326b5ff1b31Sbellard 
327b5ff1b31Sbellard     switch (offset >> 2) {
328b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
329b5ff1b31Sbellard         return s->level & s->irq_enabled;
330b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
331b5ff1b31Sbellard         return s->level;
332b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
333b5ff1b31Sbellard         return s->irq_enabled;
334b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
335b5ff1b31Sbellard         return s->level & 1;
336b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
337b5ff1b31Sbellard         return s->level & s->fiq_enabled;
338b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
339b5ff1b31Sbellard         return s->level;
340b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
341b5ff1b31Sbellard         return s->fiq_enabled;
342b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
343b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
344b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
345b5ff1b31Sbellard     default:
34629bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
347b5ff1b31Sbellard         return 0;
348b5ff1b31Sbellard     }
349b5ff1b31Sbellard }
350b5ff1b31Sbellard 
351a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
35261074e46SBenoît Canet                           uint64_t value, unsigned size)
353b5ff1b31Sbellard {
354b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
355b5ff1b31Sbellard 
356b5ff1b31Sbellard     switch (offset >> 2) {
357b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
358b5ff1b31Sbellard         s->irq_enabled |= value;
359b5ff1b31Sbellard         break;
360b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
361b5ff1b31Sbellard         s->irq_enabled &= ~value;
362b5ff1b31Sbellard         break;
363b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
364b5ff1b31Sbellard         if (value & 1)
365d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
366b5ff1b31Sbellard         break;
367b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
368b5ff1b31Sbellard         if (value & 1)
369d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
370b5ff1b31Sbellard         break;
371b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
372b5ff1b31Sbellard         s->fiq_enabled |= value;
373b5ff1b31Sbellard         break;
374b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
375b5ff1b31Sbellard         s->fiq_enabled &= ~value;
376b5ff1b31Sbellard         break;
377b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
378b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
379b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
380b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
381b5ff1b31Sbellard     default:
38229bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
383b5ff1b31Sbellard         return;
384b5ff1b31Sbellard     }
385b5ff1b31Sbellard     icp_pic_update(s);
386b5ff1b31Sbellard }
387b5ff1b31Sbellard 
38861074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
38961074e46SBenoît Canet     .read = icp_pic_read,
39061074e46SBenoît Canet     .write = icp_pic_write,
39161074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
392b5ff1b31Sbellard };
393b5ff1b31Sbellard 
39491b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
395b5ff1b31Sbellard {
39691b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
39791b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
398b5ff1b31Sbellard 
39991b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
40091b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
40191b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
40264bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
40364bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
40491b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
40581a322d4SGerd Hoffmann     return 0;
406b5ff1b31Sbellard }
407b5ff1b31Sbellard 
408b5ff1b31Sbellard /* CP control registers.  */
4090c36493eSBenoît Canet 
410ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
411ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \
412ffc8542aSJan Kiszka     OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
413ffc8542aSJan Kiszka 
414ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState {
415ffc8542aSJan Kiszka     /*< private >*/
416ffc8542aSJan Kiszka     SysBusDevice parent_obj;
417ffc8542aSJan Kiszka     /*< public >*/
418ffc8542aSJan Kiszka 
419ffc8542aSJan Kiszka     MemoryRegion iomem;
42083d0cf89SJan Kiszka 
42183d0cf89SJan Kiszka     qemu_irq mmc_irq;
42283d0cf89SJan Kiszka     uint32_t intreg_state;
423ffc8542aSJan Kiszka } ICPCtrlRegsState;
424ffc8542aSJan Kiszka 
42583d0cf89SJan Kiszka #define ICP_GPIO_MMC_WPROT      "mmc-wprot"
42683d0cf89SJan Kiszka #define ICP_GPIO_MMC_CARDIN     "mmc-cardin"
42783d0cf89SJan Kiszka 
42883d0cf89SJan Kiszka #define ICP_INTREG_WPROT        (1 << 0)
42983d0cf89SJan Kiszka #define ICP_INTREG_CARDIN       (1 << 3)
43083d0cf89SJan Kiszka 
431a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4320c36493eSBenoît Canet                                  unsigned size)
433b5ff1b31Sbellard {
43483d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
43583d0cf89SJan Kiszka 
436b5ff1b31Sbellard     switch (offset >> 2) {
437b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
438b5ff1b31Sbellard         return 0x41034003;
439b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
440b5ff1b31Sbellard         return 0;
441b5ff1b31Sbellard     case 2: /* CP_INTREG */
44283d0cf89SJan Kiszka         return s->intreg_state;
443b5ff1b31Sbellard     case 3: /* CP_DECODE */
444b5ff1b31Sbellard         return 0x11;
445b5ff1b31Sbellard     default:
4462ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
447b5ff1b31Sbellard         return 0;
448b5ff1b31Sbellard     }
449b5ff1b31Sbellard }
450b5ff1b31Sbellard 
451a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4520c36493eSBenoît Canet                           uint64_t value, unsigned size)
453b5ff1b31Sbellard {
45483d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
45583d0cf89SJan Kiszka 
456b5ff1b31Sbellard     switch (offset >> 2) {
457b5ff1b31Sbellard     case 2: /* CP_INTREG */
45883d0cf89SJan Kiszka         s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
45983d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
46083d0cf89SJan Kiszka         break;
46183d0cf89SJan Kiszka     case 1: /* CP_FLASHPROG */
462b5ff1b31Sbellard     case 3: /* CP_DECODE */
463b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
464b5ff1b31Sbellard         break;
465b5ff1b31Sbellard     default:
4662ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
467b5ff1b31Sbellard     }
468b5ff1b31Sbellard }
4690c36493eSBenoît Canet 
4700c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4710c36493eSBenoît Canet     .read = icp_control_read,
4720c36493eSBenoît Canet     .write = icp_control_write,
4730c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
474b5ff1b31Sbellard };
475b5ff1b31Sbellard 
47683d0cf89SJan Kiszka static void icp_control_mmc_wprot(void *opaque, int line, int level)
47783d0cf89SJan Kiszka {
47883d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
47983d0cf89SJan Kiszka 
48083d0cf89SJan Kiszka     s->intreg_state &= ~ICP_INTREG_WPROT;
48183d0cf89SJan Kiszka     if (level) {
48283d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_WPROT;
48383d0cf89SJan Kiszka     }
48483d0cf89SJan Kiszka }
48583d0cf89SJan Kiszka 
48683d0cf89SJan Kiszka static void icp_control_mmc_cardin(void *opaque, int line, int level)
48783d0cf89SJan Kiszka {
48883d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
48983d0cf89SJan Kiszka 
49083d0cf89SJan Kiszka     /* line is released by writing to CP_INTREG */
49183d0cf89SJan Kiszka     if (level) {
49283d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_CARDIN;
49383d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, 1);
49483d0cf89SJan Kiszka     }
49583d0cf89SJan Kiszka }
49683d0cf89SJan Kiszka 
497ffc8542aSJan Kiszka static void icp_control_init(Object *obj)
498b5ff1b31Sbellard {
499ffc8542aSJan Kiszka     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
500ffc8542aSJan Kiszka     ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
50183d0cf89SJan Kiszka     DeviceState *dev = DEVICE(obj);
502b5ff1b31Sbellard 
503ffc8542aSJan Kiszka     memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
504ffc8542aSJan Kiszka                           "icp_ctrl_regs", 0x00800000);
505ffc8542aSJan Kiszka     sysbus_init_mmio(sbd, &s->iomem);
50683d0cf89SJan Kiszka 
50783d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
50883d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
50983d0cf89SJan Kiszka                             ICP_GPIO_MMC_CARDIN, 1);
51083d0cf89SJan Kiszka     sysbus_init_irq(sbd, &s->mmc_irq);
511b5ff1b31Sbellard }
512b5ff1b31Sbellard 
513b5ff1b31Sbellard 
514b5ff1b31Sbellard /* Board init.  */
515b5ff1b31Sbellard 
516f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
517f93eb9ffSbalrog     .loader_start = 0x0,
518f93eb9ffSbalrog     .board_id = 0x113,
519f93eb9ffSbalrog };
520f93eb9ffSbalrog 
5213ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine)
522b5ff1b31Sbellard {
5233ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
5243ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
5253ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
5263ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
5273ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
528223a72f1SGreg Bellows     ObjectClass *cpu_oc;
529223a72f1SGreg Bellows     Object *cpuobj;
530393a9eabSAndreas Färber     ARMCPU *cpu;
531211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
532211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
533211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
534a7086888SPaul Brook     qemu_irq pic[32];
53583d0cf89SJan Kiszka     DeviceState *dev, *sic, *icp;
536a7086888SPaul Brook     int i;
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)) {
555007b0657SMarkus Armbruster         object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
55661e2f352SGreg Bellows     }
55761e2f352SGreg Bellows 
558007b0657SMarkus Armbruster     object_property_set_bool(cpuobj, true, "realized", &error_fatal);
559223a72f1SGreg Bellows 
560223a72f1SGreg Bellows     cpu = ARM_CPU(cpuobj);
561223a72f1SGreg Bellows 
562c8623c02SDirk Müller     memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
563c8623c02SDirk Müller                                          ram_size);
564b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
5651235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
566b5ff1b31Sbellard     /* SDRAM at address zero*/
567211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
568b5ff1b31Sbellard     /* And again at address 0x80000000 */
5692c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
570211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
571b5ff1b31Sbellard 
572257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
573ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
574e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
575a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
576a7086888SPaul Brook 
57791b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
57899d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
57999d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
58099d228d6SPeter Maydell                                 NULL);
581a7086888SPaul Brook     for (i = 0; i < 32; i++) {
582067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
583a7086888SPaul Brook     }
58483d0cf89SJan Kiszka     sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5856a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5866a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
587a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
588a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
589a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
59083d0cf89SJan Kiszka     icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
59183d0cf89SJan Kiszka                                qdev_get_gpio_in(sic, 3));
59286394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
59386394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
594b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
59583d0cf89SJan Kiszka 
59683d0cf89SJan Kiszka     dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
59783d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 0,
59883d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
59983d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 1,
60083d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
60183d0cf89SJan Kiszka 
602a005d073SStefan Hajnoczi     if (nd_table[0].used)
603d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
6042e9bdce5SPaul Brook 
6052e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
606b5ff1b31Sbellard 
607f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
608f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
609f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
610f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
6113aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
612b5ff1b31Sbellard }
613b5ff1b31Sbellard 
614e264d29dSEduardo Habkost static void integratorcp_machine_init(MachineClass *mc)
615f80f9ec9SAnthony Liguori {
616e264d29dSEduardo Habkost     mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
617e264d29dSEduardo Habkost     mc->init = integratorcp_init;
618f80f9ec9SAnthony Liguori }
619f80f9ec9SAnthony Liguori 
620e264d29dSEduardo Habkost DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
621f80f9ec9SAnthony Liguori 
622999e12bbSAnthony Liguori static Property core_properties[] = {
623257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
624bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
625999e12bbSAnthony Liguori };
626999e12bbSAnthony Liguori 
627999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
628999e12bbSAnthony Liguori {
62939bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
630999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
631999e12bbSAnthony Liguori 
632999e12bbSAnthony Liguori     k->init = integratorcm_init;
63339bffca2SAnthony Liguori     dc->props = core_properties;
634ee6847d1SGerd Hoffmann }
635999e12bbSAnthony Liguori 
6368c43a6f0SAndreas Färber static const TypeInfo core_info = {
637257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
63839bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
639257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
640999e12bbSAnthony Liguori     .class_init    = core_class_init,
641999e12bbSAnthony Liguori };
642999e12bbSAnthony Liguori 
643999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
644999e12bbSAnthony Liguori {
645999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
646999e12bbSAnthony Liguori 
647999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
648999e12bbSAnthony Liguori }
649999e12bbSAnthony Liguori 
6508c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
65191b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
65239bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
65339bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
654999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
655ee6847d1SGerd Hoffmann };
656ee6847d1SGerd Hoffmann 
657ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = {
658ffc8542aSJan Kiszka     .name          = TYPE_ICP_CONTROL_REGS,
659ffc8542aSJan Kiszka     .parent        = TYPE_SYS_BUS_DEVICE,
660ffc8542aSJan Kiszka     .instance_size = sizeof(ICPCtrlRegsState),
661ffc8542aSJan Kiszka     .instance_init = icp_control_init,
662ffc8542aSJan Kiszka };
663ffc8542aSJan Kiszka 
66483f7d43aSAndreas Färber static void integratorcp_register_types(void)
665a7086888SPaul Brook {
66639bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
66739bffca2SAnthony Liguori     type_register_static(&core_info);
668ffc8542aSJan Kiszka     type_register_static(&icp_ctrl_regs_info);
669a7086888SPaul Brook }
670a7086888SPaul Brook 
67183f7d43aSAndreas Färber type_init(integratorcp_register_types)
672