xref: /qemu/hw/arm/integratorcp.c (revision 4771d756f46219762477aaeaaef9bd215e3d5c60)
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"
12*4771d756SPaolo Bonzini #include "qemu-common.h"
13*4771d756SPaolo 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"
23b5ff1b31Sbellard 
24257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
25257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
26257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
27257ec289SAndreas Färber 
28257ec289SAndreas Färber typedef struct IntegratorCMState {
29257ec289SAndreas Färber     /*< private >*/
30257ec289SAndreas Färber     SysBusDevice parent_obj;
31257ec289SAndreas Färber     /*< public >*/
32257ec289SAndreas Färber 
3371d9bc50SBenoît Canet     MemoryRegion iomem;
34ee6847d1SGerd Hoffmann     uint32_t memsz;
35211adf4dSAvi Kivity     MemoryRegion flash;
36b5ff1b31Sbellard     uint32_t cm_osc;
37b5ff1b31Sbellard     uint32_t cm_ctrl;
38b5ff1b31Sbellard     uint32_t cm_lock;
39b5ff1b31Sbellard     uint32_t cm_auxosc;
40b5ff1b31Sbellard     uint32_t cm_sdram;
41b5ff1b31Sbellard     uint32_t cm_init;
42b5ff1b31Sbellard     uint32_t cm_flags;
43b5ff1b31Sbellard     uint32_t cm_nvflags;
44f53977f7SJan Petrous     uint32_t cm_refcnt_offset;
45b5ff1b31Sbellard     uint32_t int_level;
46b5ff1b31Sbellard     uint32_t irq_enabled;
47b5ff1b31Sbellard     uint32_t fiq_enabled;
48257ec289SAndreas Färber } IntegratorCMState;
49b5ff1b31Sbellard 
50b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
51b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
52b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
53b5ff1b31Sbellard };
54b5ff1b31Sbellard 
55a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5671d9bc50SBenoît Canet                                   unsigned size)
57b5ff1b31Sbellard {
58257ec289SAndreas Färber     IntegratorCMState *s = opaque;
59b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
60b5ff1b31Sbellard         /* CM_SPD */
61b5ff1b31Sbellard         if (offset >= 0x180)
62b5ff1b31Sbellard             return 0;
63b5ff1b31Sbellard         return integrator_spd[offset >> 2];
64b5ff1b31Sbellard     }
65b5ff1b31Sbellard     switch (offset >> 2) {
66b5ff1b31Sbellard     case 0: /* CM_ID */
67b5ff1b31Sbellard         return 0x411a3001;
68b5ff1b31Sbellard     case 1: /* CM_PROC */
69b5ff1b31Sbellard         return 0;
70b5ff1b31Sbellard     case 2: /* CM_OSC */
71b5ff1b31Sbellard         return s->cm_osc;
72b5ff1b31Sbellard     case 3: /* CM_CTRL */
73b5ff1b31Sbellard         return s->cm_ctrl;
74b5ff1b31Sbellard     case 4: /* CM_STAT */
75b5ff1b31Sbellard         return 0x00100000;
76b5ff1b31Sbellard     case 5: /* CM_LOCK */
77b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
78b5ff1b31Sbellard             return 0x1a05f;
79b5ff1b31Sbellard         } else {
80b5ff1b31Sbellard             return s->cm_lock;
81b5ff1b31Sbellard         }
82b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
83b5ff1b31Sbellard         /* ??? High frequency timer.  */
842ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
85b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
86b5ff1b31Sbellard         return s->cm_auxosc;
87b5ff1b31Sbellard     case 8: /* CM_SDRAM */
88b5ff1b31Sbellard         return s->cm_sdram;
89b5ff1b31Sbellard     case 9: /* CM_INIT */
90b5ff1b31Sbellard         return s->cm_init;
91f53977f7SJan Petrous     case 10: /* CM_REFCNT */
92f53977f7SJan Petrous         /* This register, CM_REFCNT, provides a 32-bit count value.
93f53977f7SJan Petrous          * The count increments at the fixed reference clock frequency of 24MHz
94f53977f7SJan Petrous          * and can be used as a real-time counter.
95f53977f7SJan Petrous          */
96f53977f7SJan Petrous         return (uint32_t)muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
97f53977f7SJan Petrous                                   1000) - s->cm_refcnt_offset;
98b5ff1b31Sbellard     case 12: /* CM_FLAGS */
99b5ff1b31Sbellard         return s->cm_flags;
100b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
101b5ff1b31Sbellard         return s->cm_nvflags;
102b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
103b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
104b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
105b5ff1b31Sbellard         return s->int_level;
106b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
107b5ff1b31Sbellard         return s->irq_enabled;
108b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
109b5ff1b31Sbellard         return s->int_level & 1;
110b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
111b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
112b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
113b5ff1b31Sbellard         return s->int_level;
114b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
115b5ff1b31Sbellard         return s->fiq_enabled;
116b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
117b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
118b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
119b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
120b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
121b5ff1b31Sbellard         return 0;
122b5ff1b31Sbellard     default:
1232ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1242ac71179SPaul Brook                  (int)offset);
125b5ff1b31Sbellard         return 0;
126b5ff1b31Sbellard     }
127b5ff1b31Sbellard }
128b5ff1b31Sbellard 
129257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
130b5ff1b31Sbellard {
131563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
132563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
133563c2bf3SPeter Maydell      */
134563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
135b5ff1b31Sbellard }
136b5ff1b31Sbellard 
137257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
138b5ff1b31Sbellard {
139b5ff1b31Sbellard     if (value & 8) {
140df3f457bSPeter Maydell         qemu_system_reset_request();
141b5ff1b31Sbellard     }
142df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
143df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
144df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
145df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
146df3f457bSPeter Maydell          * will swamp anything else on the terminal.
147df3f457bSPeter Maydell          */
148b5ff1b31Sbellard     }
149df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
150df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
151563c2bf3SPeter Maydell     integratorcm_do_remap(s);
152b5ff1b31Sbellard }
153b5ff1b31Sbellard 
154257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
155b5ff1b31Sbellard {
156b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
157b5ff1b31Sbellard        are active.  */
158b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1592ac71179SPaul Brook         hw_error("Core module interrupt\n");
160b5ff1b31Sbellard }
161b5ff1b31Sbellard 
162a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
16371d9bc50SBenoît Canet                                uint64_t value, unsigned size)
164b5ff1b31Sbellard {
165257ec289SAndreas Färber     IntegratorCMState *s = opaque;
166b5ff1b31Sbellard     switch (offset >> 2) {
167b5ff1b31Sbellard     case 2: /* CM_OSC */
168b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
169b5ff1b31Sbellard             s->cm_osc = value;
170b5ff1b31Sbellard         break;
171b5ff1b31Sbellard     case 3: /* CM_CTRL */
172b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
173b5ff1b31Sbellard         break;
174b5ff1b31Sbellard     case 5: /* CM_LOCK */
175b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
176b5ff1b31Sbellard         break;
177b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
178b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
179b5ff1b31Sbellard             s->cm_auxosc = value;
180b5ff1b31Sbellard         break;
181b5ff1b31Sbellard     case 8: /* CM_SDRAM */
182b5ff1b31Sbellard         s->cm_sdram = value;
183b5ff1b31Sbellard         break;
184b5ff1b31Sbellard     case 9: /* CM_INIT */
185b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
186b5ff1b31Sbellard         s->cm_init = value;
187b5ff1b31Sbellard         break;
188b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
189b5ff1b31Sbellard         s->cm_flags |= value;
190b5ff1b31Sbellard         break;
191b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
192b5ff1b31Sbellard         s->cm_flags &= ~value;
193b5ff1b31Sbellard         break;
194b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
195b5ff1b31Sbellard         s->cm_nvflags |= value;
196b5ff1b31Sbellard         break;
197b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
198b5ff1b31Sbellard         s->cm_nvflags &= ~value;
199b5ff1b31Sbellard         break;
200b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
201b5ff1b31Sbellard         s->irq_enabled |= value;
202b5ff1b31Sbellard         integratorcm_update(s);
203b5ff1b31Sbellard         break;
204b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
205b5ff1b31Sbellard         s->irq_enabled &= ~value;
206b5ff1b31Sbellard         integratorcm_update(s);
207b5ff1b31Sbellard         break;
208b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
209b5ff1b31Sbellard         s->int_level |= (value & 1);
210b5ff1b31Sbellard         integratorcm_update(s);
211b5ff1b31Sbellard         break;
212b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
213b5ff1b31Sbellard         s->int_level &= ~(value & 1);
214b5ff1b31Sbellard         integratorcm_update(s);
215b5ff1b31Sbellard         break;
216b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
217b5ff1b31Sbellard         s->fiq_enabled |= value;
218b5ff1b31Sbellard         integratorcm_update(s);
219b5ff1b31Sbellard         break;
220b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
221b5ff1b31Sbellard         s->fiq_enabled &= ~value;
222b5ff1b31Sbellard         integratorcm_update(s);
223b5ff1b31Sbellard         break;
224b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
225b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
226b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
227b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
228b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
229b5ff1b31Sbellard         break;
230b5ff1b31Sbellard     default:
2312ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2322ac71179SPaul Brook                  (int)offset);
233b5ff1b31Sbellard         break;
234b5ff1b31Sbellard     }
235b5ff1b31Sbellard }
236b5ff1b31Sbellard 
237b5ff1b31Sbellard /* Integrator/CM control registers.  */
238b5ff1b31Sbellard 
23971d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
24071d9bc50SBenoît Canet     .read = integratorcm_read,
24171d9bc50SBenoît Canet     .write = integratorcm_write,
24271d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
243b5ff1b31Sbellard };
244b5ff1b31Sbellard 
24581a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
246b5ff1b31Sbellard {
247257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
248b5ff1b31Sbellard 
249b5ff1b31Sbellard     s->cm_osc = 0x01000048;
250b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
251b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
252b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
253ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
254b5ff1b31Sbellard         integrator_spd[31] = 64;
255b5ff1b31Sbellard         s->cm_sdram |= 0x10;
256ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
257b5ff1b31Sbellard         integrator_spd[31] = 32;
258b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
259ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
260b5ff1b31Sbellard         integrator_spd[31] = 16;
261b5ff1b31Sbellard         s->cm_sdram |= 0x08;
262ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
263b5ff1b31Sbellard         integrator_spd[31] = 4;
264b5ff1b31Sbellard         s->cm_sdram |= 0x04;
265b5ff1b31Sbellard     } else {
266b5ff1b31Sbellard         integrator_spd[31] = 2;
267b5ff1b31Sbellard     }
268b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
269b5ff1b31Sbellard     s->cm_init = 0x00000112;
270f53977f7SJan Petrous     s->cm_refcnt_offset = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), 24,
271f53977f7SJan Petrous                                    1000);
27249946538SHu Tao     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000,
273f8ed85acSMarkus Armbruster                            &error_fatal);
274c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
275b5ff1b31Sbellard 
27664bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
27771d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
278750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
27971d9bc50SBenoît Canet 
280563c2bf3SPeter Maydell     integratorcm_do_remap(s);
281b5ff1b31Sbellard     /* ??? Save/restore.  */
28281a322d4SGerd Hoffmann     return 0;
283b5ff1b31Sbellard }
284b5ff1b31Sbellard 
285b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
286b5ff1b31Sbellard /* Primary interrupt controller.  */
287b5ff1b31Sbellard 
28891b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
28991b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
29091b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
29191b64626SAndreas Färber 
29291b64626SAndreas Färber typedef struct icp_pic_state {
29391b64626SAndreas Färber     /*< private >*/
29491b64626SAndreas Färber     SysBusDevice parent_obj;
29591b64626SAndreas Färber     /*< public >*/
29691b64626SAndreas Färber 
29761074e46SBenoît Canet     MemoryRegion iomem;
298b5ff1b31Sbellard     uint32_t level;
299b5ff1b31Sbellard     uint32_t irq_enabled;
300b5ff1b31Sbellard     uint32_t fiq_enabled;
301d537cf6cSpbrook     qemu_irq parent_irq;
302d537cf6cSpbrook     qemu_irq parent_fiq;
303b5ff1b31Sbellard } icp_pic_state;
304b5ff1b31Sbellard 
305b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
306b5ff1b31Sbellard {
307b5ff1b31Sbellard     uint32_t flags;
308b5ff1b31Sbellard 
309b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
310d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
311cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
312d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
313b5ff1b31Sbellard }
314b5ff1b31Sbellard 
315cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
316b5ff1b31Sbellard {
31780337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
318b5ff1b31Sbellard     if (level)
31980337b66Sbellard         s->level |= 1 << irq;
320b5ff1b31Sbellard     else
32180337b66Sbellard         s->level &= ~(1 << irq);
322b5ff1b31Sbellard     icp_pic_update(s);
323b5ff1b31Sbellard }
324b5ff1b31Sbellard 
325a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
32661074e46SBenoît Canet                              unsigned size)
327b5ff1b31Sbellard {
328b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
329b5ff1b31Sbellard 
330b5ff1b31Sbellard     switch (offset >> 2) {
331b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
332b5ff1b31Sbellard         return s->level & s->irq_enabled;
333b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
334b5ff1b31Sbellard         return s->level;
335b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
336b5ff1b31Sbellard         return s->irq_enabled;
337b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
338b5ff1b31Sbellard         return s->level & 1;
339b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
340b5ff1b31Sbellard         return s->level & s->fiq_enabled;
341b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
342b5ff1b31Sbellard         return s->level;
343b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
344b5ff1b31Sbellard         return s->fiq_enabled;
345b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
346b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
347b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
348b5ff1b31Sbellard     default:
34929bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
350b5ff1b31Sbellard         return 0;
351b5ff1b31Sbellard     }
352b5ff1b31Sbellard }
353b5ff1b31Sbellard 
354a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
35561074e46SBenoît Canet                           uint64_t value, unsigned size)
356b5ff1b31Sbellard {
357b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
358b5ff1b31Sbellard 
359b5ff1b31Sbellard     switch (offset >> 2) {
360b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
361b5ff1b31Sbellard         s->irq_enabled |= value;
362b5ff1b31Sbellard         break;
363b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
364b5ff1b31Sbellard         s->irq_enabled &= ~value;
365b5ff1b31Sbellard         break;
366b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
367b5ff1b31Sbellard         if (value & 1)
368d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
369b5ff1b31Sbellard         break;
370b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
371b5ff1b31Sbellard         if (value & 1)
372d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
373b5ff1b31Sbellard         break;
374b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
375b5ff1b31Sbellard         s->fiq_enabled |= value;
376b5ff1b31Sbellard         break;
377b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
378b5ff1b31Sbellard         s->fiq_enabled &= ~value;
379b5ff1b31Sbellard         break;
380b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
381b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
382b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
383b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
384b5ff1b31Sbellard     default:
38529bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
386b5ff1b31Sbellard         return;
387b5ff1b31Sbellard     }
388b5ff1b31Sbellard     icp_pic_update(s);
389b5ff1b31Sbellard }
390b5ff1b31Sbellard 
39161074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
39261074e46SBenoît Canet     .read = icp_pic_read,
39361074e46SBenoît Canet     .write = icp_pic_write,
39461074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
395b5ff1b31Sbellard };
396b5ff1b31Sbellard 
39791b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
398b5ff1b31Sbellard {
39991b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
40091b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
401b5ff1b31Sbellard 
40291b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
40391b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
40491b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
40564bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
40664bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
40791b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
40881a322d4SGerd Hoffmann     return 0;
409b5ff1b31Sbellard }
410b5ff1b31Sbellard 
411b5ff1b31Sbellard /* CP control registers.  */
4120c36493eSBenoît Canet 
413ffc8542aSJan Kiszka #define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
414ffc8542aSJan Kiszka #define ICP_CONTROL_REGS(obj) \
415ffc8542aSJan Kiszka     OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
416ffc8542aSJan Kiszka 
417ffc8542aSJan Kiszka typedef struct ICPCtrlRegsState {
418ffc8542aSJan Kiszka     /*< private >*/
419ffc8542aSJan Kiszka     SysBusDevice parent_obj;
420ffc8542aSJan Kiszka     /*< public >*/
421ffc8542aSJan Kiszka 
422ffc8542aSJan Kiszka     MemoryRegion iomem;
42383d0cf89SJan Kiszka 
42483d0cf89SJan Kiszka     qemu_irq mmc_irq;
42583d0cf89SJan Kiszka     uint32_t intreg_state;
426ffc8542aSJan Kiszka } ICPCtrlRegsState;
427ffc8542aSJan Kiszka 
42883d0cf89SJan Kiszka #define ICP_GPIO_MMC_WPROT      "mmc-wprot"
42983d0cf89SJan Kiszka #define ICP_GPIO_MMC_CARDIN     "mmc-cardin"
43083d0cf89SJan Kiszka 
43183d0cf89SJan Kiszka #define ICP_INTREG_WPROT        (1 << 0)
43283d0cf89SJan Kiszka #define ICP_INTREG_CARDIN       (1 << 3)
43383d0cf89SJan Kiszka 
434a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4350c36493eSBenoît Canet                                  unsigned size)
436b5ff1b31Sbellard {
43783d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
43883d0cf89SJan Kiszka 
439b5ff1b31Sbellard     switch (offset >> 2) {
440b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
441b5ff1b31Sbellard         return 0x41034003;
442b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
443b5ff1b31Sbellard         return 0;
444b5ff1b31Sbellard     case 2: /* CP_INTREG */
44583d0cf89SJan Kiszka         return s->intreg_state;
446b5ff1b31Sbellard     case 3: /* CP_DECODE */
447b5ff1b31Sbellard         return 0x11;
448b5ff1b31Sbellard     default:
4492ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
450b5ff1b31Sbellard         return 0;
451b5ff1b31Sbellard     }
452b5ff1b31Sbellard }
453b5ff1b31Sbellard 
454a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4550c36493eSBenoît Canet                           uint64_t value, unsigned size)
456b5ff1b31Sbellard {
45783d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
45883d0cf89SJan Kiszka 
459b5ff1b31Sbellard     switch (offset >> 2) {
460b5ff1b31Sbellard     case 2: /* CP_INTREG */
46183d0cf89SJan Kiszka         s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
46283d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
46383d0cf89SJan Kiszka         break;
46483d0cf89SJan Kiszka     case 1: /* CP_FLASHPROG */
465b5ff1b31Sbellard     case 3: /* CP_DECODE */
466b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
467b5ff1b31Sbellard         break;
468b5ff1b31Sbellard     default:
4692ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
470b5ff1b31Sbellard     }
471b5ff1b31Sbellard }
4720c36493eSBenoît Canet 
4730c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4740c36493eSBenoît Canet     .read = icp_control_read,
4750c36493eSBenoît Canet     .write = icp_control_write,
4760c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
477b5ff1b31Sbellard };
478b5ff1b31Sbellard 
47983d0cf89SJan Kiszka static void icp_control_mmc_wprot(void *opaque, int line, int level)
48083d0cf89SJan Kiszka {
48183d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
48283d0cf89SJan Kiszka 
48383d0cf89SJan Kiszka     s->intreg_state &= ~ICP_INTREG_WPROT;
48483d0cf89SJan Kiszka     if (level) {
48583d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_WPROT;
48683d0cf89SJan Kiszka     }
48783d0cf89SJan Kiszka }
48883d0cf89SJan Kiszka 
48983d0cf89SJan Kiszka static void icp_control_mmc_cardin(void *opaque, int line, int level)
49083d0cf89SJan Kiszka {
49183d0cf89SJan Kiszka     ICPCtrlRegsState *s = opaque;
49283d0cf89SJan Kiszka 
49383d0cf89SJan Kiszka     /* line is released by writing to CP_INTREG */
49483d0cf89SJan Kiszka     if (level) {
49583d0cf89SJan Kiszka         s->intreg_state |= ICP_INTREG_CARDIN;
49683d0cf89SJan Kiszka         qemu_set_irq(s->mmc_irq, 1);
49783d0cf89SJan Kiszka     }
49883d0cf89SJan Kiszka }
49983d0cf89SJan Kiszka 
500ffc8542aSJan Kiszka static void icp_control_init(Object *obj)
501b5ff1b31Sbellard {
502ffc8542aSJan Kiszka     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
503ffc8542aSJan Kiszka     ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
50483d0cf89SJan Kiszka     DeviceState *dev = DEVICE(obj);
505b5ff1b31Sbellard 
506ffc8542aSJan Kiszka     memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
507ffc8542aSJan Kiszka                           "icp_ctrl_regs", 0x00800000);
508ffc8542aSJan Kiszka     sysbus_init_mmio(sbd, &s->iomem);
50983d0cf89SJan Kiszka 
51083d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
51183d0cf89SJan Kiszka     qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
51283d0cf89SJan Kiszka                             ICP_GPIO_MMC_CARDIN, 1);
51383d0cf89SJan Kiszka     sysbus_init_irq(sbd, &s->mmc_irq);
514b5ff1b31Sbellard }
515b5ff1b31Sbellard 
516b5ff1b31Sbellard 
517b5ff1b31Sbellard /* Board init.  */
518b5ff1b31Sbellard 
519f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
520f93eb9ffSbalrog     .loader_start = 0x0,
521f93eb9ffSbalrog     .board_id = 0x113,
522f93eb9ffSbalrog };
523f93eb9ffSbalrog 
5243ef96221SMarcel Apfelbaum static void integratorcp_init(MachineState *machine)
525b5ff1b31Sbellard {
5263ef96221SMarcel Apfelbaum     ram_addr_t ram_size = machine->ram_size;
5273ef96221SMarcel Apfelbaum     const char *cpu_model = machine->cpu_model;
5283ef96221SMarcel Apfelbaum     const char *kernel_filename = machine->kernel_filename;
5293ef96221SMarcel Apfelbaum     const char *kernel_cmdline = machine->kernel_cmdline;
5303ef96221SMarcel Apfelbaum     const char *initrd_filename = machine->initrd_filename;
531223a72f1SGreg Bellows     ObjectClass *cpu_oc;
532223a72f1SGreg Bellows     Object *cpuobj;
533393a9eabSAndreas Färber     ARMCPU *cpu;
534211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
535211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
536211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
537a7086888SPaul Brook     qemu_irq pic[32];
53883d0cf89SJan Kiszka     DeviceState *dev, *sic, *icp;
539a7086888SPaul Brook     int i;
540b5ff1b31Sbellard 
541393a9eabSAndreas Färber     if (!cpu_model) {
5423371d272Spbrook         cpu_model = "arm926";
543393a9eabSAndreas Färber     }
544223a72f1SGreg Bellows 
545223a72f1SGreg Bellows     cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
546223a72f1SGreg Bellows     if (!cpu_oc) {
547aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
548aaed909aSbellard         exit(1);
549aaed909aSbellard     }
550393a9eabSAndreas Färber 
551223a72f1SGreg Bellows     cpuobj = object_new(object_class_get_name(cpu_oc));
552223a72f1SGreg Bellows 
55361e2f352SGreg Bellows     /* By default ARM1176 CPUs have EL3 enabled.  This board does not
55461e2f352SGreg Bellows      * currently support EL3 so the CPU EL3 property is disabled before
55561e2f352SGreg Bellows      * realization.
55661e2f352SGreg Bellows      */
55761e2f352SGreg Bellows     if (object_property_find(cpuobj, "has_el3", NULL)) {
558007b0657SMarkus Armbruster         object_property_set_bool(cpuobj, false, "has_el3", &error_fatal);
55961e2f352SGreg Bellows     }
56061e2f352SGreg Bellows 
561007b0657SMarkus Armbruster     object_property_set_bool(cpuobj, true, "realized", &error_fatal);
562223a72f1SGreg Bellows 
563223a72f1SGreg Bellows     cpu = ARM_CPU(cpuobj);
564223a72f1SGreg Bellows 
565c8623c02SDirk Müller     memory_region_allocate_system_memory(ram, NULL, "integrator.ram",
566c8623c02SDirk Müller                                          ram_size);
567b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
5681235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
569b5ff1b31Sbellard     /* SDRAM at address zero*/
570211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
571b5ff1b31Sbellard     /* And again at address 0x80000000 */
5722c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
573211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
574b5ff1b31Sbellard 
575257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
576ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
577e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
578a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
579a7086888SPaul Brook 
58091b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
58199d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
58299d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
58399d228d6SPeter Maydell                                 NULL);
584a7086888SPaul Brook     for (i = 0; i < 32; i++) {
585067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
586a7086888SPaul Brook     }
58783d0cf89SJan Kiszka     sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5886a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5896a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
590a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
591a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
592a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
59383d0cf89SJan Kiszka     icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
59483d0cf89SJan Kiszka                                qdev_get_gpio_in(sic, 3));
59586394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
59686394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
597b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
59883d0cf89SJan Kiszka 
59983d0cf89SJan Kiszka     dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
60083d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 0,
60183d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
60283d0cf89SJan Kiszka     qdev_connect_gpio_out(dev, 1,
60383d0cf89SJan Kiszka                           qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
60483d0cf89SJan Kiszka 
605a005d073SStefan Hajnoczi     if (nd_table[0].used)
606d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
6072e9bdce5SPaul Brook 
6082e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
609b5ff1b31Sbellard 
610f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
611f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
612f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
613f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
6143aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
615b5ff1b31Sbellard }
616b5ff1b31Sbellard 
617e264d29dSEduardo Habkost static void integratorcp_machine_init(MachineClass *mc)
618f80f9ec9SAnthony Liguori {
619e264d29dSEduardo Habkost     mc->desc = "ARM Integrator/CP (ARM926EJ-S)";
620e264d29dSEduardo Habkost     mc->init = integratorcp_init;
621f80f9ec9SAnthony Liguori }
622f80f9ec9SAnthony Liguori 
623e264d29dSEduardo Habkost DEFINE_MACHINE("integratorcp", integratorcp_machine_init)
624f80f9ec9SAnthony Liguori 
625999e12bbSAnthony Liguori static Property core_properties[] = {
626257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
627bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
628999e12bbSAnthony Liguori };
629999e12bbSAnthony Liguori 
630999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
631999e12bbSAnthony Liguori {
63239bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
633999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
634999e12bbSAnthony Liguori 
635999e12bbSAnthony Liguori     k->init = integratorcm_init;
63639bffca2SAnthony Liguori     dc->props = core_properties;
637ee6847d1SGerd Hoffmann }
638999e12bbSAnthony Liguori 
6398c43a6f0SAndreas Färber static const TypeInfo core_info = {
640257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
64139bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
642257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
643999e12bbSAnthony Liguori     .class_init    = core_class_init,
644999e12bbSAnthony Liguori };
645999e12bbSAnthony Liguori 
646999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
647999e12bbSAnthony Liguori {
648999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
649999e12bbSAnthony Liguori 
650999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
651999e12bbSAnthony Liguori }
652999e12bbSAnthony Liguori 
6538c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
65491b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
65539bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
65639bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
657999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
658ee6847d1SGerd Hoffmann };
659ee6847d1SGerd Hoffmann 
660ffc8542aSJan Kiszka static const TypeInfo icp_ctrl_regs_info = {
661ffc8542aSJan Kiszka     .name          = TYPE_ICP_CONTROL_REGS,
662ffc8542aSJan Kiszka     .parent        = TYPE_SYS_BUS_DEVICE,
663ffc8542aSJan Kiszka     .instance_size = sizeof(ICPCtrlRegsState),
664ffc8542aSJan Kiszka     .instance_init = icp_control_init,
665ffc8542aSJan Kiszka };
666ffc8542aSJan Kiszka 
66783f7d43aSAndreas Färber static void integratorcp_register_types(void)
668a7086888SPaul Brook {
66939bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
67039bffca2SAnthony Liguori     type_register_static(&core_info);
671ffc8542aSJan Kiszka     type_register_static(&icp_ctrl_regs_info);
672a7086888SPaul Brook }
673a7086888SPaul Brook 
67483f7d43aSAndreas Färber type_init(integratorcp_register_types)
675