1
2
3
4
5
6
7
8
9
10#include "sysbus.h"
11#include "arm-misc.h"
12#include "primecell.h"
13#include "devices.h"
14#include "net.h"
15#include "sysemu.h"
16#include "pci.h"
17#include "usb-ohci.h"
18#include "boards.h"
19#include "blockdev.h"
20
21
22
23typedef struct vpb_sic_state
24{
25 SysBusDevice busdev;
26 uint32_t level;
27 uint32_t mask;
28 uint32_t pic_enable;
29 qemu_irq parent[32];
30 int irq;
31} vpb_sic_state;
32
33static const VMStateDescription vmstate_vpb_sic = {
34 .name = "versatilepb_sic",
35 .version_id = 1,
36 .minimum_version_id = 1,
37 .fields = (VMStateField[]) {
38 VMSTATE_UINT32(level, vpb_sic_state),
39 VMSTATE_UINT32(mask, vpb_sic_state),
40 VMSTATE_UINT32(pic_enable, vpb_sic_state),
41 VMSTATE_END_OF_LIST()
42 }
43};
44
45static void vpb_sic_update(vpb_sic_state *s)
46{
47 uint32_t flags;
48
49 flags = s->level & s->mask;
50 qemu_set_irq(s->parent[s->irq], flags != 0);
51}
52
53static void vpb_sic_update_pic(vpb_sic_state *s)
54{
55 int i;
56 uint32_t mask;
57
58 for (i = 21; i <= 30; i++) {
59 mask = 1u << i;
60 if (!(s->pic_enable & mask))
61 continue;
62 qemu_set_irq(s->parent[i], (s->level & mask) != 0);
63 }
64}
65
66static void vpb_sic_set_irq(void *opaque, int irq, int level)
67{
68 vpb_sic_state *s = (vpb_sic_state *)opaque;
69 if (level)
70 s->level |= 1u << irq;
71 else
72 s->level &= ~(1u << irq);
73 if (s->pic_enable & (1u << irq))
74 qemu_set_irq(s->parent[irq], level);
75 vpb_sic_update(s);
76}
77
78static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
79{
80 vpb_sic_state *s = (vpb_sic_state *)opaque;
81
82 switch (offset >> 2) {
83 case 0:
84 return s->level & s->mask;
85 case 1:
86 return s->level;
87 case 2:
88 return s->mask;
89 case 4:
90 return s->level & 1;
91 case 8:
92 return s->pic_enable;
93 default:
94 printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
95 return 0;
96 }
97}
98
99static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
100 uint32_t value)
101{
102 vpb_sic_state *s = (vpb_sic_state *)opaque;
103
104 switch (offset >> 2) {
105 case 2:
106 s->mask |= value;
107 break;
108 case 3:
109 s->mask &= ~value;
110 break;
111 case 4:
112 if (value)
113 s->mask |= 1;
114 break;
115 case 5:
116 if (value)
117 s->mask &= ~1u;
118 break;
119 case 8:
120 s->pic_enable |= (value & 0x7fe00000);
121 vpb_sic_update_pic(s);
122 break;
123 case 9:
124 s->pic_enable &= ~value;
125 vpb_sic_update_pic(s);
126 break;
127 default:
128 printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
129 return;
130 }
131 vpb_sic_update(s);
132}
133
134static CPUReadMemoryFunc * const vpb_sic_readfn[] = {
135 vpb_sic_read,
136 vpb_sic_read,
137 vpb_sic_read
138};
139
140static CPUWriteMemoryFunc * const vpb_sic_writefn[] = {
141 vpb_sic_write,
142 vpb_sic_write,
143 vpb_sic_write
144};
145
146static int vpb_sic_init(SysBusDevice *dev)
147{
148 vpb_sic_state *s = FROM_SYSBUS(vpb_sic_state, dev);
149 int iomemtype;
150 int i;
151
152 qdev_init_gpio_in(&dev->qdev, vpb_sic_set_irq, 32);
153 for (i = 0; i < 32; i++) {
154 sysbus_init_irq(dev, &s->parent[i]);
155 }
156 s->irq = 31;
157 iomemtype = cpu_register_io_memory(vpb_sic_readfn,
158 vpb_sic_writefn, s,
159 DEVICE_NATIVE_ENDIAN);
160 sysbus_init_mmio(dev, 0x1000, iomemtype);
161 return 0;
162}
163
164
165
166
167
168
169
170static struct arm_boot_info versatile_binfo;
171
172static void versatile_init(ram_addr_t ram_size,
173 const char *boot_device,
174 const char *kernel_filename, const char *kernel_cmdline,
175 const char *initrd_filename, const char *cpu_model,
176 int board_id)
177{
178 CPUState *env;
179 ram_addr_t ram_offset;
180 qemu_irq *cpu_pic;
181 qemu_irq pic[32];
182 qemu_irq sic[32];
183 DeviceState *dev;
184 PCIBus *pci_bus;
185 NICInfo *nd;
186 int n;
187 int done_smc = 0;
188
189 if (!cpu_model)
190 cpu_model = "arm926";
191 env = cpu_init(cpu_model);
192 if (!env) {
193 fprintf(stderr, "Unable to find CPU definition\n");
194 exit(1);
195 }
196 ram_offset = qemu_ram_alloc(NULL, "versatile.ram", ram_size);
197
198
199 cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
200
201 arm_sysctl_init(0x10000000, 0x41007004, 0x02000000);
202 cpu_pic = arm_pic_init_cpu(env);
203 dev = sysbus_create_varargs("pl190", 0x10140000,
204 cpu_pic[0], cpu_pic[1], NULL);
205 for (n = 0; n < 32; n++) {
206 pic[n] = qdev_get_gpio_in(dev, n);
207 }
208 dev = sysbus_create_simple("versatilepb_sic", 0x10003000, NULL);
209 for (n = 0; n < 32; n++) {
210 sysbus_connect_irq(sysbus_from_qdev(dev), n, pic[n]);
211 sic[n] = qdev_get_gpio_in(dev, n);
212 }
213
214 sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
215 sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
216
217 dev = sysbus_create_varargs("versatile_pci", 0x40000000,
218 sic[27], sic[28], sic[29], sic[30], NULL);
219 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
220
221
222
223 for(n = 0; n < nb_nics; n++) {
224 nd = &nd_table[n];
225
226 if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
227 smc91c111_init(nd, 0x10010000, sic[25]);
228 done_smc = 1;
229 } else {
230 pci_nic_init_nofail(nd, "rtl8139", NULL);
231 }
232 }
233 if (usb_enabled) {
234 usb_ohci_init_pci(pci_bus, -1);
235 }
236 n = drive_get_max_bus(IF_SCSI);
237 while (n >= 0) {
238 pci_create_simple(pci_bus, -1, "lsi53c895a");
239 n--;
240 }
241
242 sysbus_create_simple("pl011", 0x101f1000, pic[12]);
243 sysbus_create_simple("pl011", 0x101f2000, pic[13]);
244 sysbus_create_simple("pl011", 0x101f3000, pic[14]);
245 sysbus_create_simple("pl011", 0x10009000, sic[6]);
246
247 sysbus_create_simple("pl080", 0x10130000, pic[17]);
248 sysbus_create_simple("sp804", 0x101e2000, pic[4]);
249 sysbus_create_simple("sp804", 0x101e3000, pic[5]);
250
251
252
253 sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
254
255 sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
256 sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
257
258
259 sysbus_create_simple("pl031", 0x101e8000, pic[10]);
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297 versatile_binfo.ram_size = ram_size;
298 versatile_binfo.kernel_filename = kernel_filename;
299 versatile_binfo.kernel_cmdline = kernel_cmdline;
300 versatile_binfo.initrd_filename = initrd_filename;
301 versatile_binfo.board_id = board_id;
302 arm_load_kernel(env, &versatile_binfo);
303}
304
305static void vpb_init(ram_addr_t ram_size,
306 const char *boot_device,
307 const char *kernel_filename, const char *kernel_cmdline,
308 const char *initrd_filename, const char *cpu_model)
309{
310 versatile_init(ram_size,
311 boot_device,
312 kernel_filename, kernel_cmdline,
313 initrd_filename, cpu_model, 0x183);
314}
315
316static void vab_init(ram_addr_t ram_size,
317 const char *boot_device,
318 const char *kernel_filename, const char *kernel_cmdline,
319 const char *initrd_filename, const char *cpu_model)
320{
321 versatile_init(ram_size,
322 boot_device,
323 kernel_filename, kernel_cmdline,
324 initrd_filename, cpu_model, 0x25e);
325}
326
327static QEMUMachine versatilepb_machine = {
328 .name = "versatilepb",
329 .desc = "ARM Versatile/PB (ARM926EJ-S)",
330 .init = vpb_init,
331 .use_scsi = 1,
332};
333
334static QEMUMachine versatileab_machine = {
335 .name = "versatileab",
336 .desc = "ARM Versatile/AB (ARM926EJ-S)",
337 .init = vab_init,
338 .use_scsi = 1,
339};
340
341static void versatile_machine_init(void)
342{
343 qemu_register_machine(&versatilepb_machine);
344 qemu_register_machine(&versatileab_machine);
345}
346
347machine_init(versatile_machine_init);
348
349static SysBusDeviceInfo vpb_sic_info = {
350 .init = vpb_sic_init,
351 .qdev.name = "versatilepb_sic",
352 .qdev.size = sizeof(vpb_sic_state),
353 .qdev.vmsd = &vmstate_vpb_sic,
354 .qdev.no_user = 1,
355};
356
357static void versatilepb_register_devices(void)
358{
359 sysbus_register_withprop(&vpb_sic_info);
360}
361
362device_init(versatilepb_register_devices)
363