1
2
3
4
5
6
7
8
9
10#include "hw/sysbus.h"
11#include "hw/arm/arm.h"
12#include "hw/devices.h"
13#include "net/net.h"
14#include "sysemu/sysemu.h"
15#include "hw/pci/pci.h"
16#include "hw/i2c/i2c.h"
17#include "hw/boards.h"
18#include "sysemu/block-backend.h"
19#include "exec/address-spaces.h"
20#include "hw/block/flash.h"
21#include "qemu/error-report.h"
22
23#define VERSATILE_FLASH_ADDR 0x34000000
24#define VERSATILE_FLASH_SIZE (64 * 1024 * 1024)
25#define VERSATILE_FLASH_SECT_SIZE (256 * 1024)
26
27
28
29#define TYPE_VERSATILE_PB_SIC "versatilepb_sic"
30#define VERSATILE_PB_SIC(obj) \
31 OBJECT_CHECK(vpb_sic_state, (obj), TYPE_VERSATILE_PB_SIC)
32
33typedef struct vpb_sic_state {
34 SysBusDevice parent_obj;
35
36 MemoryRegion iomem;
37 uint32_t level;
38 uint32_t mask;
39 uint32_t pic_enable;
40 qemu_irq parent[32];
41 int irq;
42} vpb_sic_state;
43
44static const VMStateDescription vmstate_vpb_sic = {
45 .name = "versatilepb_sic",
46 .version_id = 1,
47 .minimum_version_id = 1,
48 .fields = (VMStateField[]) {
49 VMSTATE_UINT32(level, vpb_sic_state),
50 VMSTATE_UINT32(mask, vpb_sic_state),
51 VMSTATE_UINT32(pic_enable, vpb_sic_state),
52 VMSTATE_END_OF_LIST()
53 }
54};
55
56static void vpb_sic_update(vpb_sic_state *s)
57{
58 uint32_t flags;
59
60 flags = s->level & s->mask;
61 qemu_set_irq(s->parent[s->irq], flags != 0);
62}
63
64static void vpb_sic_update_pic(vpb_sic_state *s)
65{
66 int i;
67 uint32_t mask;
68
69 for (i = 21; i <= 30; i++) {
70 mask = 1u << i;
71 if (!(s->pic_enable & mask))
72 continue;
73 qemu_set_irq(s->parent[i], (s->level & mask) != 0);
74 }
75}
76
77static void vpb_sic_set_irq(void *opaque, int irq, int level)
78{
79 vpb_sic_state *s = (vpb_sic_state *)opaque;
80 if (level)
81 s->level |= 1u << irq;
82 else
83 s->level &= ~(1u << irq);
84 if (s->pic_enable & (1u << irq))
85 qemu_set_irq(s->parent[irq], level);
86 vpb_sic_update(s);
87}
88
89static uint64_t vpb_sic_read(void *opaque, hwaddr offset,
90 unsigned size)
91{
92 vpb_sic_state *s = (vpb_sic_state *)opaque;
93
94 switch (offset >> 2) {
95 case 0:
96 return s->level & s->mask;
97 case 1:
98 return s->level;
99 case 2:
100 return s->mask;
101 case 4:
102 return s->level & 1;
103 case 8:
104 return s->pic_enable;
105 default:
106 printf ("vpb_sic_read: Bad register offset 0x%x\n", (int)offset);
107 return 0;
108 }
109}
110
111static void vpb_sic_write(void *opaque, hwaddr offset,
112 uint64_t value, unsigned size)
113{
114 vpb_sic_state *s = (vpb_sic_state *)opaque;
115
116 switch (offset >> 2) {
117 case 2:
118 s->mask |= value;
119 break;
120 case 3:
121 s->mask &= ~value;
122 break;
123 case 4:
124 if (value)
125 s->mask |= 1;
126 break;
127 case 5:
128 if (value)
129 s->mask &= ~1u;
130 break;
131 case 8:
132 s->pic_enable |= (value & 0x7fe00000);
133 vpb_sic_update_pic(s);
134 break;
135 case 9:
136 s->pic_enable &= ~value;
137 vpb_sic_update_pic(s);
138 break;
139 default:
140 printf ("vpb_sic_write: Bad register offset 0x%x\n", (int)offset);
141 return;
142 }
143 vpb_sic_update(s);
144}
145
146static const MemoryRegionOps vpb_sic_ops = {
147 .read = vpb_sic_read,
148 .write = vpb_sic_write,
149 .endianness = DEVICE_NATIVE_ENDIAN,
150};
151
152static int vpb_sic_init(SysBusDevice *sbd)
153{
154 DeviceState *dev = DEVICE(sbd);
155 vpb_sic_state *s = VERSATILE_PB_SIC(dev);
156 int i;
157
158 qdev_init_gpio_in(dev, vpb_sic_set_irq, 32);
159 for (i = 0; i < 32; i++) {
160 sysbus_init_irq(sbd, &s->parent[i]);
161 }
162 s->irq = 31;
163 memory_region_init_io(&s->iomem, OBJECT(s), &vpb_sic_ops, s,
164 "vpb-sic", 0x1000);
165 sysbus_init_mmio(sbd, &s->iomem);
166 return 0;
167}
168
169
170
171
172
173
174
175static struct arm_boot_info versatile_binfo;
176
177static void versatile_init(MachineState *machine, int board_id)
178{
179 ObjectClass *cpu_oc;
180 Object *cpuobj;
181 ARMCPU *cpu;
182 MemoryRegion *sysmem = get_system_memory();
183 MemoryRegion *ram = g_new(MemoryRegion, 1);
184 qemu_irq pic[32];
185 qemu_irq sic[32];
186 DeviceState *dev, *sysctl;
187 SysBusDevice *busdev;
188 DeviceState *pl041;
189 PCIBus *pci_bus;
190 NICInfo *nd;
191 I2CBus *i2c;
192 int n;
193 int done_smc = 0;
194 DriveInfo *dinfo;
195 Error *err = NULL;
196
197 if (!machine->cpu_model) {
198 machine->cpu_model = "arm926";
199 }
200
201 cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, machine->cpu_model);
202 if (!cpu_oc) {
203 fprintf(stderr, "Unable to find CPU definition\n");
204 exit(1);
205 }
206
207 cpuobj = object_new(object_class_get_name(cpu_oc));
208
209
210
211
212
213 if (object_property_find(cpuobj, "has_el3", NULL)) {
214 object_property_set_bool(cpuobj, false, "has_el3", &err);
215 if (err) {
216 error_report_err(err);
217 exit(1);
218 }
219 }
220
221 object_property_set_bool(cpuobj, true, "realized", &err);
222 if (err) {
223 error_report_err(err);
224 exit(1);
225 }
226
227 cpu = ARM_CPU(cpuobj);
228
229 memory_region_allocate_system_memory(ram, NULL, "versatile.ram",
230 machine->ram_size);
231
232
233 memory_region_add_subregion(sysmem, 0, ram);
234
235 sysctl = qdev_create(NULL, "realview_sysctl");
236 qdev_prop_set_uint32(sysctl, "sys_id", 0x41007004);
237 qdev_prop_set_uint32(sysctl, "proc_id", 0x02000000);
238 qdev_init_nofail(sysctl);
239 sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000);
240
241 dev = sysbus_create_varargs("pl190", 0x10140000,
242 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_IRQ),
243 qdev_get_gpio_in(DEVICE(cpu), ARM_CPU_FIQ),
244 NULL);
245 for (n = 0; n < 32; n++) {
246 pic[n] = qdev_get_gpio_in(dev, n);
247 }
248 dev = sysbus_create_simple(TYPE_VERSATILE_PB_SIC, 0x10003000, NULL);
249 for (n = 0; n < 32; n++) {
250 sysbus_connect_irq(SYS_BUS_DEVICE(dev), n, pic[n]);
251 sic[n] = qdev_get_gpio_in(dev, n);
252 }
253
254 sysbus_create_simple("pl050_keyboard", 0x10006000, sic[3]);
255 sysbus_create_simple("pl050_mouse", 0x10007000, sic[4]);
256
257 dev = qdev_create(NULL, "versatile_pci");
258 busdev = SYS_BUS_DEVICE(dev);
259 qdev_init_nofail(dev);
260 sysbus_mmio_map(busdev, 0, 0x10001000);
261 sysbus_mmio_map(busdev, 1, 0x41000000);
262 sysbus_mmio_map(busdev, 2, 0x42000000);
263 sysbus_mmio_map(busdev, 3, 0x43000000);
264 sysbus_mmio_map(busdev, 4, 0x44000000);
265 sysbus_mmio_map(busdev, 5, 0x50000000);
266 sysbus_mmio_map(busdev, 6, 0x60000000);
267 sysbus_connect_irq(busdev, 0, sic[27]);
268 sysbus_connect_irq(busdev, 1, sic[28]);
269 sysbus_connect_irq(busdev, 2, sic[29]);
270 sysbus_connect_irq(busdev, 3, sic[30]);
271 pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
272
273 for(n = 0; n < nb_nics; n++) {
274 nd = &nd_table[n];
275
276 if (!done_smc && (!nd->model || strcmp(nd->model, "smc91c111") == 0)) {
277 smc91c111_init(nd, 0x10010000, sic[25]);
278 done_smc = 1;
279 } else {
280 pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
281 }
282 }
283 if (usb_enabled()) {
284 pci_create_simple(pci_bus, -1, "pci-ohci");
285 }
286 n = drive_get_max_bus(IF_SCSI);
287 while (n >= 0) {
288 pci_create_simple(pci_bus, -1, "lsi53c895a");
289 n--;
290 }
291
292 sysbus_create_simple("pl011", 0x101f1000, pic[12]);
293 sysbus_create_simple("pl011", 0x101f2000, pic[13]);
294 sysbus_create_simple("pl011", 0x101f3000, pic[14]);
295 sysbus_create_simple("pl011", 0x10009000, sic[6]);
296
297 sysbus_create_simple("pl080", 0x10130000, pic[17]);
298 sysbus_create_simple("sp804", 0x101e2000, pic[4]);
299 sysbus_create_simple("sp804", 0x101e3000, pic[5]);
300
301 sysbus_create_simple("pl061", 0x101e4000, pic[6]);
302 sysbus_create_simple("pl061", 0x101e5000, pic[7]);
303 sysbus_create_simple("pl061", 0x101e6000, pic[8]);
304 sysbus_create_simple("pl061", 0x101e7000, pic[9]);
305
306
307
308 dev = sysbus_create_simple("pl110_versatile", 0x10120000, pic[16]);
309
310 qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
311
312 sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
313 sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
314
315
316 sysbus_create_simple("pl031", 0x101e8000, pic[10]);
317
318 dev = sysbus_create_simple("versatile_i2c", 0x10002000, NULL);
319 i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c");
320 i2c_create_slave(i2c, "ds1338", 0x68);
321
322
323 pl041 = qdev_create(NULL, "pl041");
324 qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512);
325 qdev_init_nofail(pl041);
326 sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, 0x10004000);
327 sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, sic[24]);
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366 dinfo = drive_get(IF_PFLASH, 0, 0);
367 if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
368 VERSATILE_FLASH_SIZE,
369 dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
370 VERSATILE_FLASH_SECT_SIZE,
371 VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
372 4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
373 fprintf(stderr, "qemu: Error registering flash memory.\n");
374 }
375
376 versatile_binfo.ram_size = machine->ram_size;
377 versatile_binfo.kernel_filename = machine->kernel_filename;
378 versatile_binfo.kernel_cmdline = machine->kernel_cmdline;
379 versatile_binfo.initrd_filename = machine->initrd_filename;
380 versatile_binfo.board_id = board_id;
381 arm_load_kernel(cpu, &versatile_binfo);
382}
383
384static void vpb_init(MachineState *machine)
385{
386 versatile_init(machine, 0x183);
387}
388
389static void vab_init(MachineState *machine)
390{
391 versatile_init(machine, 0x25e);
392}
393
394static void versatilepb_class_init(ObjectClass *oc, void *data)
395{
396 MachineClass *mc = MACHINE_CLASS(oc);
397
398 mc->desc = "ARM Versatile/PB (ARM926EJ-S)";
399 mc->init = vpb_init;
400 mc->block_default_type = IF_SCSI;
401}
402
403static const TypeInfo versatilepb_type = {
404 .name = MACHINE_TYPE_NAME("versatilepb"),
405 .parent = TYPE_MACHINE,
406 .class_init = versatilepb_class_init,
407};
408
409static void versatileab_class_init(ObjectClass *oc, void *data)
410{
411 MachineClass *mc = MACHINE_CLASS(oc);
412
413 mc->desc = "ARM Versatile/AB (ARM926EJ-S)";
414 mc->init = vab_init;
415 mc->block_default_type = IF_SCSI;
416}
417
418static const TypeInfo versatileab_type = {
419 .name = MACHINE_TYPE_NAME("versatileab"),
420 .parent = TYPE_MACHINE,
421 .class_init = versatileab_class_init,
422};
423
424static void versatile_machine_init(void)
425{
426 type_register_static(&versatilepb_type);
427 type_register_static(&versatileab_type);
428}
429
430machine_init(versatile_machine_init)
431
432static void vpb_sic_class_init(ObjectClass *klass, void *data)
433{
434 DeviceClass *dc = DEVICE_CLASS(klass);
435 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
436
437 k->init = vpb_sic_init;
438 dc->vmsd = &vmstate_vpb_sic;
439}
440
441static const TypeInfo vpb_sic_info = {
442 .name = TYPE_VERSATILE_PB_SIC,
443 .parent = TYPE_SYS_BUS_DEVICE,
444 .instance_size = sizeof(vpb_sic_state),
445 .class_init = vpb_sic_class_init,
446};
447
448static void versatilepb_register_types(void)
449{
450 type_register_static(&vpb_sic_info);
451}
452
453type_init(versatilepb_register_types)
454