xref: /qemu/hw/arm/integratorcp.c (revision b86160555f8d1fe11d6bcec393e08e645d7e1e8d)
1b5ff1b31Sbellard /*
2b5ff1b31Sbellard  * ARM Integrator CP System emulation.
3b5ff1b31Sbellard  *
4a1bb27b1Spbrook  * Copyright (c) 2005-2007 CodeSourcery.
5b5ff1b31Sbellard  * Written by Paul Brook
6b5ff1b31Sbellard  *
78e31bf38SMatthew Fernandez  * This code is licensed under the GPL
8b5ff1b31Sbellard  */
9b5ff1b31Sbellard 
1083c9f4caSPaolo Bonzini #include "hw/sysbus.h"
11bd2be150SPeter Maydell #include "hw/devices.h"
1283c9f4caSPaolo Bonzini #include "hw/boards.h"
13bd2be150SPeter Maydell #include "hw/arm/arm.h"
14*b8616055SAlex Bennée #include "hw/misc/arm_integrator_debug.h"
151422e32dSPaolo Bonzini #include "net/net.h"
16022c62cbSPaolo Bonzini #include "exec/address-spaces.h"
179c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
18b5ff1b31Sbellard 
19257ec289SAndreas Färber #define TYPE_INTEGRATOR_CM "integrator_core"
20257ec289SAndreas Färber #define INTEGRATOR_CM(obj) \
21257ec289SAndreas Färber     OBJECT_CHECK(IntegratorCMState, (obj), TYPE_INTEGRATOR_CM)
22257ec289SAndreas Färber 
23257ec289SAndreas Färber typedef struct IntegratorCMState {
24257ec289SAndreas Färber     /*< private >*/
25257ec289SAndreas Färber     SysBusDevice parent_obj;
26257ec289SAndreas Färber     /*< public >*/
27257ec289SAndreas Färber 
2871d9bc50SBenoît Canet     MemoryRegion iomem;
29ee6847d1SGerd Hoffmann     uint32_t memsz;
30211adf4dSAvi Kivity     MemoryRegion flash;
31b5ff1b31Sbellard     uint32_t cm_osc;
32b5ff1b31Sbellard     uint32_t cm_ctrl;
33b5ff1b31Sbellard     uint32_t cm_lock;
34b5ff1b31Sbellard     uint32_t cm_auxosc;
35b5ff1b31Sbellard     uint32_t cm_sdram;
36b5ff1b31Sbellard     uint32_t cm_init;
37b5ff1b31Sbellard     uint32_t cm_flags;
38b5ff1b31Sbellard     uint32_t cm_nvflags;
39b5ff1b31Sbellard     uint32_t int_level;
40b5ff1b31Sbellard     uint32_t irq_enabled;
41b5ff1b31Sbellard     uint32_t fiq_enabled;
42257ec289SAndreas Färber } IntegratorCMState;
43b5ff1b31Sbellard 
44b5ff1b31Sbellard static uint8_t integrator_spd[128] = {
45b5ff1b31Sbellard    128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
46b5ff1b31Sbellard    0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
47b5ff1b31Sbellard };
48b5ff1b31Sbellard 
49a8170e5eSAvi Kivity static uint64_t integratorcm_read(void *opaque, hwaddr offset,
5071d9bc50SBenoît Canet                                   unsigned size)
51b5ff1b31Sbellard {
52257ec289SAndreas Färber     IntegratorCMState *s = opaque;
53b5ff1b31Sbellard     if (offset >= 0x100 && offset < 0x200) {
54b5ff1b31Sbellard         /* CM_SPD */
55b5ff1b31Sbellard         if (offset >= 0x180)
56b5ff1b31Sbellard             return 0;
57b5ff1b31Sbellard         return integrator_spd[offset >> 2];
58b5ff1b31Sbellard     }
59b5ff1b31Sbellard     switch (offset >> 2) {
60b5ff1b31Sbellard     case 0: /* CM_ID */
61b5ff1b31Sbellard         return 0x411a3001;
62b5ff1b31Sbellard     case 1: /* CM_PROC */
63b5ff1b31Sbellard         return 0;
64b5ff1b31Sbellard     case 2: /* CM_OSC */
65b5ff1b31Sbellard         return s->cm_osc;
66b5ff1b31Sbellard     case 3: /* CM_CTRL */
67b5ff1b31Sbellard         return s->cm_ctrl;
68b5ff1b31Sbellard     case 4: /* CM_STAT */
69b5ff1b31Sbellard         return 0x00100000;
70b5ff1b31Sbellard     case 5: /* CM_LOCK */
71b5ff1b31Sbellard         if (s->cm_lock == 0xa05f) {
72b5ff1b31Sbellard             return 0x1a05f;
73b5ff1b31Sbellard         } else {
74b5ff1b31Sbellard             return s->cm_lock;
75b5ff1b31Sbellard         }
76b5ff1b31Sbellard     case 6: /* CM_LMBUSCNT */
77b5ff1b31Sbellard         /* ??? High frequency timer.  */
782ac71179SPaul Brook         hw_error("integratorcm_read: CM_LMBUSCNT");
79b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
80b5ff1b31Sbellard         return s->cm_auxosc;
81b5ff1b31Sbellard     case 8: /* CM_SDRAM */
82b5ff1b31Sbellard         return s->cm_sdram;
83b5ff1b31Sbellard     case 9: /* CM_INIT */
84b5ff1b31Sbellard         return s->cm_init;
85b5ff1b31Sbellard     case 10: /* CM_REFCT */
86b5ff1b31Sbellard         /* ??? High frequency timer.  */
872ac71179SPaul Brook         hw_error("integratorcm_read: CM_REFCT");
88b5ff1b31Sbellard     case 12: /* CM_FLAGS */
89b5ff1b31Sbellard         return s->cm_flags;
90b5ff1b31Sbellard     case 14: /* CM_NVFLAGS */
91b5ff1b31Sbellard         return s->cm_nvflags;
92b5ff1b31Sbellard     case 16: /* CM_IRQ_STAT */
93b5ff1b31Sbellard         return s->int_level & s->irq_enabled;
94b5ff1b31Sbellard     case 17: /* CM_IRQ_RSTAT */
95b5ff1b31Sbellard         return s->int_level;
96b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
97b5ff1b31Sbellard         return s->irq_enabled;
98b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
99b5ff1b31Sbellard         return s->int_level & 1;
100b5ff1b31Sbellard     case 24: /* CM_FIQ_STAT */
101b5ff1b31Sbellard         return s->int_level & s->fiq_enabled;
102b5ff1b31Sbellard     case 25: /* CM_FIQ_RSTAT */
103b5ff1b31Sbellard         return s->int_level;
104b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
105b5ff1b31Sbellard         return s->fiq_enabled;
106b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
107b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
108b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
109b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
110b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
111b5ff1b31Sbellard         return 0;
112b5ff1b31Sbellard     default:
1132ac71179SPaul Brook         hw_error("integratorcm_read: Unimplemented offset 0x%x\n",
1142ac71179SPaul Brook                  (int)offset);
115b5ff1b31Sbellard         return 0;
116b5ff1b31Sbellard     }
117b5ff1b31Sbellard }
118b5ff1b31Sbellard 
119257ec289SAndreas Färber static void integratorcm_do_remap(IntegratorCMState *s)
120b5ff1b31Sbellard {
121563c2bf3SPeter Maydell     /* Sync memory region state with CM_CTRL REMAP bit:
122563c2bf3SPeter Maydell      * bit 0 => flash at address 0; bit 1 => RAM
123563c2bf3SPeter Maydell      */
124563c2bf3SPeter Maydell     memory_region_set_enabled(&s->flash, !(s->cm_ctrl & 4));
125b5ff1b31Sbellard }
126b5ff1b31Sbellard 
127257ec289SAndreas Färber static void integratorcm_set_ctrl(IntegratorCMState *s, uint32_t value)
128b5ff1b31Sbellard {
129b5ff1b31Sbellard     if (value & 8) {
130df3f457bSPeter Maydell         qemu_system_reset_request();
131b5ff1b31Sbellard     }
132df3f457bSPeter Maydell     if ((s->cm_ctrl ^ value) & 1) {
133df3f457bSPeter Maydell         /* (value & 1) != 0 means the green "MISC LED" is lit.
134df3f457bSPeter Maydell          * We don't have any nice place to display LEDs. printf is a bad
135df3f457bSPeter Maydell          * idea because Linux uses the LED as a heartbeat and the output
136df3f457bSPeter Maydell          * will swamp anything else on the terminal.
137df3f457bSPeter Maydell          */
138b5ff1b31Sbellard     }
139df3f457bSPeter Maydell     /* Note that the RESET bit [3] always reads as zero */
140df3f457bSPeter Maydell     s->cm_ctrl = (s->cm_ctrl & ~5) | (value & 5);
141563c2bf3SPeter Maydell     integratorcm_do_remap(s);
142b5ff1b31Sbellard }
143b5ff1b31Sbellard 
144257ec289SAndreas Färber static void integratorcm_update(IntegratorCMState *s)
145b5ff1b31Sbellard {
146b5ff1b31Sbellard     /* ??? The CPU irq/fiq is raised when either the core module or base PIC
147b5ff1b31Sbellard        are active.  */
148b5ff1b31Sbellard     if (s->int_level & (s->irq_enabled | s->fiq_enabled))
1492ac71179SPaul Brook         hw_error("Core module interrupt\n");
150b5ff1b31Sbellard }
151b5ff1b31Sbellard 
152a8170e5eSAvi Kivity static void integratorcm_write(void *opaque, hwaddr offset,
15371d9bc50SBenoît Canet                                uint64_t value, unsigned size)
154b5ff1b31Sbellard {
155257ec289SAndreas Färber     IntegratorCMState *s = opaque;
156b5ff1b31Sbellard     switch (offset >> 2) {
157b5ff1b31Sbellard     case 2: /* CM_OSC */
158b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
159b5ff1b31Sbellard             s->cm_osc = value;
160b5ff1b31Sbellard         break;
161b5ff1b31Sbellard     case 3: /* CM_CTRL */
162b5ff1b31Sbellard         integratorcm_set_ctrl(s, value);
163b5ff1b31Sbellard         break;
164b5ff1b31Sbellard     case 5: /* CM_LOCK */
165b5ff1b31Sbellard         s->cm_lock = value & 0xffff;
166b5ff1b31Sbellard         break;
167b5ff1b31Sbellard     case 7: /* CM_AUXOSC */
168b5ff1b31Sbellard         if (s->cm_lock == 0xa05f)
169b5ff1b31Sbellard             s->cm_auxosc = value;
170b5ff1b31Sbellard         break;
171b5ff1b31Sbellard     case 8: /* CM_SDRAM */
172b5ff1b31Sbellard         s->cm_sdram = value;
173b5ff1b31Sbellard         break;
174b5ff1b31Sbellard     case 9: /* CM_INIT */
175b5ff1b31Sbellard         /* ??? This can change the memory bus frequency.  */
176b5ff1b31Sbellard         s->cm_init = value;
177b5ff1b31Sbellard         break;
178b5ff1b31Sbellard     case 12: /* CM_FLAGSS */
179b5ff1b31Sbellard         s->cm_flags |= value;
180b5ff1b31Sbellard         break;
181b5ff1b31Sbellard     case 13: /* CM_FLAGSC */
182b5ff1b31Sbellard         s->cm_flags &= ~value;
183b5ff1b31Sbellard         break;
184b5ff1b31Sbellard     case 14: /* CM_NVFLAGSS */
185b5ff1b31Sbellard         s->cm_nvflags |= value;
186b5ff1b31Sbellard         break;
187b5ff1b31Sbellard     case 15: /* CM_NVFLAGSS */
188b5ff1b31Sbellard         s->cm_nvflags &= ~value;
189b5ff1b31Sbellard         break;
190b5ff1b31Sbellard     case 18: /* CM_IRQ_ENSET */
191b5ff1b31Sbellard         s->irq_enabled |= value;
192b5ff1b31Sbellard         integratorcm_update(s);
193b5ff1b31Sbellard         break;
194b5ff1b31Sbellard     case 19: /* CM_IRQ_ENCLR */
195b5ff1b31Sbellard         s->irq_enabled &= ~value;
196b5ff1b31Sbellard         integratorcm_update(s);
197b5ff1b31Sbellard         break;
198b5ff1b31Sbellard     case 20: /* CM_SOFT_INTSET */
199b5ff1b31Sbellard         s->int_level |= (value & 1);
200b5ff1b31Sbellard         integratorcm_update(s);
201b5ff1b31Sbellard         break;
202b5ff1b31Sbellard     case 21: /* CM_SOFT_INTCLR */
203b5ff1b31Sbellard         s->int_level &= ~(value & 1);
204b5ff1b31Sbellard         integratorcm_update(s);
205b5ff1b31Sbellard         break;
206b5ff1b31Sbellard     case 26: /* CM_FIQ_ENSET */
207b5ff1b31Sbellard         s->fiq_enabled |= value;
208b5ff1b31Sbellard         integratorcm_update(s);
209b5ff1b31Sbellard         break;
210b5ff1b31Sbellard     case 27: /* CM_FIQ_ENCLR */
211b5ff1b31Sbellard         s->fiq_enabled &= ~value;
212b5ff1b31Sbellard         integratorcm_update(s);
213b5ff1b31Sbellard         break;
214b5ff1b31Sbellard     case 32: /* CM_VOLTAGE_CTL0 */
215b5ff1b31Sbellard     case 33: /* CM_VOLTAGE_CTL1 */
216b5ff1b31Sbellard     case 34: /* CM_VOLTAGE_CTL2 */
217b5ff1b31Sbellard     case 35: /* CM_VOLTAGE_CTL3 */
218b5ff1b31Sbellard         /* ??? Voltage control unimplemented.  */
219b5ff1b31Sbellard         break;
220b5ff1b31Sbellard     default:
2212ac71179SPaul Brook         hw_error("integratorcm_write: Unimplemented offset 0x%x\n",
2222ac71179SPaul Brook                  (int)offset);
223b5ff1b31Sbellard         break;
224b5ff1b31Sbellard     }
225b5ff1b31Sbellard }
226b5ff1b31Sbellard 
227b5ff1b31Sbellard /* Integrator/CM control registers.  */
228b5ff1b31Sbellard 
22971d9bc50SBenoît Canet static const MemoryRegionOps integratorcm_ops = {
23071d9bc50SBenoît Canet     .read = integratorcm_read,
23171d9bc50SBenoît Canet     .write = integratorcm_write,
23271d9bc50SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
233b5ff1b31Sbellard };
234b5ff1b31Sbellard 
23581a322d4SGerd Hoffmann static int integratorcm_init(SysBusDevice *dev)
236b5ff1b31Sbellard {
237257ec289SAndreas Färber     IntegratorCMState *s = INTEGRATOR_CM(dev);
238b5ff1b31Sbellard 
239b5ff1b31Sbellard     s->cm_osc = 0x01000048;
240b5ff1b31Sbellard     /* ??? What should the high bits of this value be?  */
241b5ff1b31Sbellard     s->cm_auxosc = 0x0007feff;
242b5ff1b31Sbellard     s->cm_sdram = 0x00011122;
243ee6847d1SGerd Hoffmann     if (s->memsz >= 256) {
244b5ff1b31Sbellard         integrator_spd[31] = 64;
245b5ff1b31Sbellard         s->cm_sdram |= 0x10;
246ee6847d1SGerd Hoffmann     } else if (s->memsz >= 128) {
247b5ff1b31Sbellard         integrator_spd[31] = 32;
248b5ff1b31Sbellard         s->cm_sdram |= 0x0c;
249ee6847d1SGerd Hoffmann     } else if (s->memsz >= 64) {
250b5ff1b31Sbellard         integrator_spd[31] = 16;
251b5ff1b31Sbellard         s->cm_sdram |= 0x08;
252ee6847d1SGerd Hoffmann     } else if (s->memsz >= 32) {
253b5ff1b31Sbellard         integrator_spd[31] = 4;
254b5ff1b31Sbellard         s->cm_sdram |= 0x04;
255b5ff1b31Sbellard     } else {
256b5ff1b31Sbellard         integrator_spd[31] = 2;
257b5ff1b31Sbellard     }
258b5ff1b31Sbellard     memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
259b5ff1b31Sbellard     s->cm_init = 0x00000112;
26064bde0f3SPaolo Bonzini     memory_region_init_ram(&s->flash, OBJECT(s), "integrator.flash", 0x100000);
261c5705a77SAvi Kivity     vmstate_register_ram_global(&s->flash);
262b5ff1b31Sbellard 
26364bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &integratorcm_ops, s,
26471d9bc50SBenoît Canet                           "integratorcm", 0x00800000);
265750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->iomem);
26671d9bc50SBenoît Canet 
267563c2bf3SPeter Maydell     integratorcm_do_remap(s);
268b5ff1b31Sbellard     /* ??? Save/restore.  */
26981a322d4SGerd Hoffmann     return 0;
270b5ff1b31Sbellard }
271b5ff1b31Sbellard 
272b5ff1b31Sbellard /* Integrator/CP hardware emulation.  */
273b5ff1b31Sbellard /* Primary interrupt controller.  */
274b5ff1b31Sbellard 
27591b64626SAndreas Färber #define TYPE_INTEGRATOR_PIC "integrator_pic"
27691b64626SAndreas Färber #define INTEGRATOR_PIC(obj) \
27791b64626SAndreas Färber    OBJECT_CHECK(icp_pic_state, (obj), TYPE_INTEGRATOR_PIC)
27891b64626SAndreas Färber 
27991b64626SAndreas Färber typedef struct icp_pic_state {
28091b64626SAndreas Färber     /*< private >*/
28191b64626SAndreas Färber     SysBusDevice parent_obj;
28291b64626SAndreas Färber     /*< public >*/
28391b64626SAndreas Färber 
28461074e46SBenoît Canet     MemoryRegion iomem;
285b5ff1b31Sbellard     uint32_t level;
286b5ff1b31Sbellard     uint32_t irq_enabled;
287b5ff1b31Sbellard     uint32_t fiq_enabled;
288d537cf6cSpbrook     qemu_irq parent_irq;
289d537cf6cSpbrook     qemu_irq parent_fiq;
290b5ff1b31Sbellard } icp_pic_state;
291b5ff1b31Sbellard 
292b5ff1b31Sbellard static void icp_pic_update(icp_pic_state *s)
293b5ff1b31Sbellard {
294b5ff1b31Sbellard     uint32_t flags;
295b5ff1b31Sbellard 
296b5ff1b31Sbellard     flags = (s->level & s->irq_enabled);
297d537cf6cSpbrook     qemu_set_irq(s->parent_irq, flags != 0);
298cdbdb648Spbrook     flags = (s->level & s->fiq_enabled);
299d537cf6cSpbrook     qemu_set_irq(s->parent_fiq, flags != 0);
300b5ff1b31Sbellard }
301b5ff1b31Sbellard 
302cdbdb648Spbrook static void icp_pic_set_irq(void *opaque, int irq, int level)
303b5ff1b31Sbellard {
30480337b66Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
305b5ff1b31Sbellard     if (level)
30680337b66Sbellard         s->level |= 1 << irq;
307b5ff1b31Sbellard     else
30880337b66Sbellard         s->level &= ~(1 << irq);
309b5ff1b31Sbellard     icp_pic_update(s);
310b5ff1b31Sbellard }
311b5ff1b31Sbellard 
312a8170e5eSAvi Kivity static uint64_t icp_pic_read(void *opaque, hwaddr offset,
31361074e46SBenoît Canet                              unsigned size)
314b5ff1b31Sbellard {
315b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
316b5ff1b31Sbellard 
317b5ff1b31Sbellard     switch (offset >> 2) {
318b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
319b5ff1b31Sbellard         return s->level & s->irq_enabled;
320b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
321b5ff1b31Sbellard         return s->level;
322b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
323b5ff1b31Sbellard         return s->irq_enabled;
324b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
325b5ff1b31Sbellard         return s->level & 1;
326b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
327b5ff1b31Sbellard         return s->level & s->fiq_enabled;
328b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
329b5ff1b31Sbellard         return s->level;
330b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
331b5ff1b31Sbellard         return s->fiq_enabled;
332b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
333b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
334b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
335b5ff1b31Sbellard     default:
33629bfb117Spbrook         printf ("icp_pic_read: Bad register offset 0x%x\n", (int)offset);
337b5ff1b31Sbellard         return 0;
338b5ff1b31Sbellard     }
339b5ff1b31Sbellard }
340b5ff1b31Sbellard 
341a8170e5eSAvi Kivity static void icp_pic_write(void *opaque, hwaddr offset,
34261074e46SBenoît Canet                           uint64_t value, unsigned size)
343b5ff1b31Sbellard {
344b5ff1b31Sbellard     icp_pic_state *s = (icp_pic_state *)opaque;
345b5ff1b31Sbellard 
346b5ff1b31Sbellard     switch (offset >> 2) {
347b5ff1b31Sbellard     case 2: /* IRQ_ENABLESET */
348b5ff1b31Sbellard         s->irq_enabled |= value;
349b5ff1b31Sbellard         break;
350b5ff1b31Sbellard     case 3: /* IRQ_ENABLECLR */
351b5ff1b31Sbellard         s->irq_enabled &= ~value;
352b5ff1b31Sbellard         break;
353b5ff1b31Sbellard     case 4: /* INT_SOFTSET */
354b5ff1b31Sbellard         if (value & 1)
355d537cf6cSpbrook             icp_pic_set_irq(s, 0, 1);
356b5ff1b31Sbellard         break;
357b5ff1b31Sbellard     case 5: /* INT_SOFTCLR */
358b5ff1b31Sbellard         if (value & 1)
359d537cf6cSpbrook             icp_pic_set_irq(s, 0, 0);
360b5ff1b31Sbellard         break;
361b5ff1b31Sbellard     case 10: /* FRQ_ENABLESET */
362b5ff1b31Sbellard         s->fiq_enabled |= value;
363b5ff1b31Sbellard         break;
364b5ff1b31Sbellard     case 11: /* FRQ_ENABLECLR */
365b5ff1b31Sbellard         s->fiq_enabled &= ~value;
366b5ff1b31Sbellard         break;
367b5ff1b31Sbellard     case 0: /* IRQ_STATUS */
368b5ff1b31Sbellard     case 1: /* IRQ_RAWSTAT */
369b5ff1b31Sbellard     case 8: /* FRQ_STATUS */
370b5ff1b31Sbellard     case 9: /* FRQ_RAWSTAT */
371b5ff1b31Sbellard     default:
37229bfb117Spbrook         printf ("icp_pic_write: Bad register offset 0x%x\n", (int)offset);
373b5ff1b31Sbellard         return;
374b5ff1b31Sbellard     }
375b5ff1b31Sbellard     icp_pic_update(s);
376b5ff1b31Sbellard }
377b5ff1b31Sbellard 
37861074e46SBenoît Canet static const MemoryRegionOps icp_pic_ops = {
37961074e46SBenoît Canet     .read = icp_pic_read,
38061074e46SBenoît Canet     .write = icp_pic_write,
38161074e46SBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
382b5ff1b31Sbellard };
383b5ff1b31Sbellard 
38491b64626SAndreas Färber static int icp_pic_init(SysBusDevice *sbd)
385b5ff1b31Sbellard {
38691b64626SAndreas Färber     DeviceState *dev = DEVICE(sbd);
38791b64626SAndreas Färber     icp_pic_state *s = INTEGRATOR_PIC(dev);
388b5ff1b31Sbellard 
38991b64626SAndreas Färber     qdev_init_gpio_in(dev, icp_pic_set_irq, 32);
39091b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_irq);
39191b64626SAndreas Färber     sysbus_init_irq(sbd, &s->parent_fiq);
39264bde0f3SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &icp_pic_ops, s,
39364bde0f3SPaolo Bonzini                           "icp-pic", 0x00800000);
39491b64626SAndreas Färber     sysbus_init_mmio(sbd, &s->iomem);
39581a322d4SGerd Hoffmann     return 0;
396b5ff1b31Sbellard }
397b5ff1b31Sbellard 
398b5ff1b31Sbellard /* CP control registers.  */
3990c36493eSBenoît Canet 
400a8170e5eSAvi Kivity static uint64_t icp_control_read(void *opaque, hwaddr offset,
4010c36493eSBenoît Canet                                  unsigned size)
402b5ff1b31Sbellard {
403b5ff1b31Sbellard     switch (offset >> 2) {
404b5ff1b31Sbellard     case 0: /* CP_IDFIELD */
405b5ff1b31Sbellard         return 0x41034003;
406b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
407b5ff1b31Sbellard         return 0;
408b5ff1b31Sbellard     case 2: /* CP_INTREG */
409b5ff1b31Sbellard         return 0;
410b5ff1b31Sbellard     case 3: /* CP_DECODE */
411b5ff1b31Sbellard         return 0x11;
412b5ff1b31Sbellard     default:
4132ac71179SPaul Brook         hw_error("icp_control_read: Bad offset %x\n", (int)offset);
414b5ff1b31Sbellard         return 0;
415b5ff1b31Sbellard     }
416b5ff1b31Sbellard }
417b5ff1b31Sbellard 
418a8170e5eSAvi Kivity static void icp_control_write(void *opaque, hwaddr offset,
4190c36493eSBenoît Canet                           uint64_t value, unsigned size)
420b5ff1b31Sbellard {
421b5ff1b31Sbellard     switch (offset >> 2) {
422b5ff1b31Sbellard     case 1: /* CP_FLASHPROG */
423b5ff1b31Sbellard     case 2: /* CP_INTREG */
424b5ff1b31Sbellard     case 3: /* CP_DECODE */
425b5ff1b31Sbellard         /* Nothing interesting implemented yet.  */
426b5ff1b31Sbellard         break;
427b5ff1b31Sbellard     default:
4282ac71179SPaul Brook         hw_error("icp_control_write: Bad offset %x\n", (int)offset);
429b5ff1b31Sbellard     }
430b5ff1b31Sbellard }
4310c36493eSBenoît Canet 
4320c36493eSBenoît Canet static const MemoryRegionOps icp_control_ops = {
4330c36493eSBenoît Canet     .read = icp_control_read,
4340c36493eSBenoît Canet     .write = icp_control_write,
4350c36493eSBenoît Canet     .endianness = DEVICE_NATIVE_ENDIAN,
436b5ff1b31Sbellard };
437b5ff1b31Sbellard 
438a8170e5eSAvi Kivity static void icp_control_init(hwaddr base)
439b5ff1b31Sbellard {
4400c36493eSBenoît Canet     MemoryRegion *io;
441b5ff1b31Sbellard 
4420c36493eSBenoît Canet     io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
4432c9b15caSPaolo Bonzini     memory_region_init_io(io, NULL, &icp_control_ops, NULL,
4440c36493eSBenoît Canet                           "control", 0x00800000);
4450c36493eSBenoît Canet     memory_region_add_subregion(get_system_memory(), base, io);
446b5ff1b31Sbellard     /* ??? Save/restore.  */
447b5ff1b31Sbellard }
448b5ff1b31Sbellard 
449b5ff1b31Sbellard 
450b5ff1b31Sbellard /* Board init.  */
451b5ff1b31Sbellard 
452f93eb9ffSbalrog static struct arm_boot_info integrator_binfo = {
453f93eb9ffSbalrog     .loader_start = 0x0,
454f93eb9ffSbalrog     .board_id = 0x113,
455f93eb9ffSbalrog };
456f93eb9ffSbalrog 
4575f072e1fSEduardo Habkost static void integratorcp_init(QEMUMachineInitArgs *args)
458b5ff1b31Sbellard {
4595f072e1fSEduardo Habkost     ram_addr_t ram_size = args->ram_size;
4605f072e1fSEduardo Habkost     const char *cpu_model = args->cpu_model;
4615f072e1fSEduardo Habkost     const char *kernel_filename = args->kernel_filename;
4625f072e1fSEduardo Habkost     const char *kernel_cmdline = args->kernel_cmdline;
4635f072e1fSEduardo Habkost     const char *initrd_filename = args->initrd_filename;
464393a9eabSAndreas Färber     ARMCPU *cpu;
465211adf4dSAvi Kivity     MemoryRegion *address_space_mem = get_system_memory();
466211adf4dSAvi Kivity     MemoryRegion *ram = g_new(MemoryRegion, 1);
467211adf4dSAvi Kivity     MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
468a7086888SPaul Brook     qemu_irq pic[32];
469a7086888SPaul Brook     DeviceState *dev;
470a7086888SPaul Brook     int i;
471b5ff1b31Sbellard 
472393a9eabSAndreas Färber     if (!cpu_model) {
4733371d272Spbrook         cpu_model = "arm926";
474393a9eabSAndreas Färber     }
475393a9eabSAndreas Färber     cpu = cpu_arm_init(cpu_model);
476393a9eabSAndreas Färber     if (!cpu) {
477aaed909aSbellard         fprintf(stderr, "Unable to find CPU definition\n");
478aaed909aSbellard         exit(1);
479aaed909aSbellard     }
480393a9eabSAndreas Färber 
4812c9b15caSPaolo Bonzini     memory_region_init_ram(ram, NULL, "integrator.ram", ram_size);
482c5705a77SAvi Kivity     vmstate_register_ram_global(ram);
483b5ff1b31Sbellard     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
4841235fc06Sths     /* ??? RAM should repeat to fill physical memory space.  */
485b5ff1b31Sbellard     /* SDRAM at address zero*/
486211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0, ram);
487b5ff1b31Sbellard     /* And again at address 0x80000000 */
4882c9b15caSPaolo Bonzini     memory_region_init_alias(ram_alias, NULL, "ram.alias", ram, 0, ram_size);
489211adf4dSAvi Kivity     memory_region_add_subregion(address_space_mem, 0x80000000, ram_alias);
490b5ff1b31Sbellard 
491257ec289SAndreas Färber     dev = qdev_create(NULL, TYPE_INTEGRATOR_CM);
492ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "memsz", ram_size >> 20);
493e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
494a7086888SPaul Brook     sysbus_mmio_map((SysBusDevice *)dev, 0, 0x10000000);
495a7086888SPaul Brook 
49691b64626SAndreas Färber     dev = sysbus_create_varargs(TYPE_INTEGRATOR_PIC, 0x14000000,
49799d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
49899d228d6SPeter Maydell                                 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
49999d228d6SPeter Maydell                                 NULL);
500a7086888SPaul Brook     for (i = 0; i < 32; i++) {
501067a3ddcSPaul Brook         pic[i] = qdev_get_gpio_in(dev, i);
502a7086888SPaul Brook     }
50391b64626SAndreas Färber     sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
5046a824ec3SPaul Brook     sysbus_create_varargs("integrator_pit", 0x13000000,
5056a824ec3SPaul Brook                           pic[5], pic[6], pic[7], NULL);
506a63bdb31SPaul Brook     sysbus_create_simple("pl031", 0x15000000, pic[8]);
507a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x16000000, pic[1]);
508a7d518a6SPaul Brook     sysbus_create_simple("pl011", 0x17000000, pic[2]);
509b5ff1b31Sbellard     icp_control_init(0xcb000000);
51086394e96SPaul Brook     sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
51186394e96SPaul Brook     sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
512*b8616055SAlex Bennée     sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
513aa9311d8SPaul Brook     sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
514a005d073SStefan Hajnoczi     if (nd_table[0].used)
515d537cf6cSpbrook         smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
5162e9bdce5SPaul Brook 
5172e9bdce5SPaul Brook     sysbus_create_simple("pl110", 0xc0000000, pic[22]);
518b5ff1b31Sbellard 
519f93eb9ffSbalrog     integrator_binfo.ram_size = ram_size;
520f93eb9ffSbalrog     integrator_binfo.kernel_filename = kernel_filename;
521f93eb9ffSbalrog     integrator_binfo.kernel_cmdline = kernel_cmdline;
522f93eb9ffSbalrog     integrator_binfo.initrd_filename = initrd_filename;
5233aaa8dfaSAndreas Färber     arm_load_kernel(cpu, &integrator_binfo);
524b5ff1b31Sbellard }
525b5ff1b31Sbellard 
526f80f9ec9SAnthony Liguori static QEMUMachine integratorcp_machine = {
5274b32e168Saliguori     .name = "integratorcp",
5284b32e168Saliguori     .desc = "ARM Integrator/CP (ARM926EJ-S)",
5294b32e168Saliguori     .init = integratorcp_init,
5300c257437SAnthony Liguori     .is_default = 1,
531b5ff1b31Sbellard };
532a7086888SPaul Brook 
533f80f9ec9SAnthony Liguori static void integratorcp_machine_init(void)
534f80f9ec9SAnthony Liguori {
535f80f9ec9SAnthony Liguori     qemu_register_machine(&integratorcp_machine);
536f80f9ec9SAnthony Liguori }
537f80f9ec9SAnthony Liguori 
538f80f9ec9SAnthony Liguori machine_init(integratorcp_machine_init);
539f80f9ec9SAnthony Liguori 
540999e12bbSAnthony Liguori static Property core_properties[] = {
541257ec289SAndreas Färber     DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0),
542bb36f66aSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
543999e12bbSAnthony Liguori };
544999e12bbSAnthony Liguori 
545999e12bbSAnthony Liguori static void core_class_init(ObjectClass *klass, void *data)
546999e12bbSAnthony Liguori {
54739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
548999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
549999e12bbSAnthony Liguori 
550999e12bbSAnthony Liguori     k->init = integratorcm_init;
55139bffca2SAnthony Liguori     dc->props = core_properties;
552ee6847d1SGerd Hoffmann }
553999e12bbSAnthony Liguori 
5548c43a6f0SAndreas Färber static const TypeInfo core_info = {
555257ec289SAndreas Färber     .name          = TYPE_INTEGRATOR_CM,
55639bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
557257ec289SAndreas Färber     .instance_size = sizeof(IntegratorCMState),
558999e12bbSAnthony Liguori     .class_init    = core_class_init,
559999e12bbSAnthony Liguori };
560999e12bbSAnthony Liguori 
561999e12bbSAnthony Liguori static void icp_pic_class_init(ObjectClass *klass, void *data)
562999e12bbSAnthony Liguori {
563999e12bbSAnthony Liguori     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
564999e12bbSAnthony Liguori 
565999e12bbSAnthony Liguori     sdc->init = icp_pic_init;
566999e12bbSAnthony Liguori }
567999e12bbSAnthony Liguori 
5688c43a6f0SAndreas Färber static const TypeInfo icp_pic_info = {
56991b64626SAndreas Färber     .name          = TYPE_INTEGRATOR_PIC,
57039bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
57139bffca2SAnthony Liguori     .instance_size = sizeof(icp_pic_state),
572999e12bbSAnthony Liguori     .class_init    = icp_pic_class_init,
573ee6847d1SGerd Hoffmann };
574ee6847d1SGerd Hoffmann 
57583f7d43aSAndreas Färber static void integratorcp_register_types(void)
576a7086888SPaul Brook {
57739bffca2SAnthony Liguori     type_register_static(&icp_pic_info);
57839bffca2SAnthony Liguori     type_register_static(&core_info);
579a7086888SPaul Brook }
580a7086888SPaul Brook 
58183f7d43aSAndreas Färber type_init(integratorcp_register_types)
582