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