1 | /* |
2 | * ARM Versatile Express emulation. |
3 | * |
4 | * Copyright (c) 2010 - 2011 B Labs Ltd. |
5 | * Copyright (c) 2011 Linaro Limited |
6 | * Written by Bahadir Balban, Amit Mahajan, Peter Maydell |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; if not, see <http://www.gnu.org/licenses/>. |
19 | * |
20 | * Contributions after 2012-01-13 are licensed under the terms of the |
21 | * GNU GPL, version 2 or (at your option) any later version. |
22 | */ |
23 | |
24 | #include "qemu/osdep.h" |
25 | #include "qapi/error.h" |
26 | #include "qemu-common.h" |
27 | #include "cpu.h" |
28 | #include "hw/sysbus.h" |
29 | #include "hw/arm/boot.h" |
30 | #include "hw/arm/primecell.h" |
31 | #include "hw/net/lan9118.h" |
32 | #include "hw/i2c/i2c.h" |
33 | #include "net/net.h" |
34 | #include "sysemu/sysemu.h" |
35 | #include "hw/boards.h" |
36 | #include "hw/loader.h" |
37 | #include "exec/address-spaces.h" |
38 | #include "hw/block/flash.h" |
39 | #include "sysemu/device_tree.h" |
40 | #include "qemu/error-report.h" |
41 | #include <libfdt.h> |
42 | #include "hw/char/pl011.h" |
43 | #include "hw/cpu/a9mpcore.h" |
44 | #include "hw/cpu/a15mpcore.h" |
45 | |
46 | #define VEXPRESS_BOARD_ID 0x8e0 |
47 | #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) |
48 | #define VEXPRESS_FLASH_SECT_SIZE (256 * 1024) |
49 | |
50 | /* Number of virtio transports to create (0..8; limited by |
51 | * number of available IRQ lines). |
52 | */ |
53 | #define NUM_VIRTIO_TRANSPORTS 4 |
54 | |
55 | /* Address maps for peripherals: |
56 | * the Versatile Express motherboard has two possible maps, |
57 | * the "legacy" one (used for A9) and the "Cortex-A Series" |
58 | * map (used for newer cores). |
59 | * Individual daughterboards can also have different maps for |
60 | * their peripherals. |
61 | */ |
62 | |
63 | enum { |
64 | VE_SYSREGS, |
65 | VE_SP810, |
66 | VE_SERIALPCI, |
67 | VE_PL041, |
68 | VE_MMCI, |
69 | VE_KMI0, |
70 | VE_KMI1, |
71 | VE_UART0, |
72 | VE_UART1, |
73 | VE_UART2, |
74 | VE_UART3, |
75 | VE_WDT, |
76 | VE_TIMER01, |
77 | VE_TIMER23, |
78 | VE_SERIALDVI, |
79 | VE_RTC, |
80 | VE_COMPACTFLASH, |
81 | VE_CLCD, |
82 | VE_NORFLASH0, |
83 | VE_NORFLASH1, |
84 | VE_NORFLASHALIAS, |
85 | VE_SRAM, |
86 | VE_VIDEORAM, |
87 | VE_ETHERNET, |
88 | VE_USB, |
89 | VE_DAPROM, |
90 | VE_VIRTIO, |
91 | }; |
92 | |
93 | static hwaddr motherboard_legacy_map[] = { |
94 | [VE_NORFLASHALIAS] = 0, |
95 | /* CS7: 0x10000000 .. 0x10020000 */ |
96 | [VE_SYSREGS] = 0x10000000, |
97 | [VE_SP810] = 0x10001000, |
98 | [VE_SERIALPCI] = 0x10002000, |
99 | [VE_PL041] = 0x10004000, |
100 | [VE_MMCI] = 0x10005000, |
101 | [VE_KMI0] = 0x10006000, |
102 | [VE_KMI1] = 0x10007000, |
103 | [VE_UART0] = 0x10009000, |
104 | [VE_UART1] = 0x1000a000, |
105 | [VE_UART2] = 0x1000b000, |
106 | [VE_UART3] = 0x1000c000, |
107 | [VE_WDT] = 0x1000f000, |
108 | [VE_TIMER01] = 0x10011000, |
109 | [VE_TIMER23] = 0x10012000, |
110 | [VE_VIRTIO] = 0x10013000, |
111 | [VE_SERIALDVI] = 0x10016000, |
112 | [VE_RTC] = 0x10017000, |
113 | [VE_COMPACTFLASH] = 0x1001a000, |
114 | [VE_CLCD] = 0x1001f000, |
115 | /* CS0: 0x40000000 .. 0x44000000 */ |
116 | [VE_NORFLASH0] = 0x40000000, |
117 | /* CS1: 0x44000000 .. 0x48000000 */ |
118 | [VE_NORFLASH1] = 0x44000000, |
119 | /* CS2: 0x48000000 .. 0x4a000000 */ |
120 | [VE_SRAM] = 0x48000000, |
121 | /* CS3: 0x4c000000 .. 0x50000000 */ |
122 | [VE_VIDEORAM] = 0x4c000000, |
123 | [VE_ETHERNET] = 0x4e000000, |
124 | [VE_USB] = 0x4f000000, |
125 | }; |
126 | |
127 | static hwaddr motherboard_aseries_map[] = { |
128 | [VE_NORFLASHALIAS] = 0, |
129 | /* CS0: 0x08000000 .. 0x0c000000 */ |
130 | [VE_NORFLASH0] = 0x08000000, |
131 | /* CS4: 0x0c000000 .. 0x10000000 */ |
132 | [VE_NORFLASH1] = 0x0c000000, |
133 | /* CS5: 0x10000000 .. 0x14000000 */ |
134 | /* CS1: 0x14000000 .. 0x18000000 */ |
135 | [VE_SRAM] = 0x14000000, |
136 | /* CS2: 0x18000000 .. 0x1c000000 */ |
137 | [VE_VIDEORAM] = 0x18000000, |
138 | [VE_ETHERNET] = 0x1a000000, |
139 | [VE_USB] = 0x1b000000, |
140 | /* CS3: 0x1c000000 .. 0x20000000 */ |
141 | [VE_DAPROM] = 0x1c000000, |
142 | [VE_SYSREGS] = 0x1c010000, |
143 | [VE_SP810] = 0x1c020000, |
144 | [VE_SERIALPCI] = 0x1c030000, |
145 | [VE_PL041] = 0x1c040000, |
146 | [VE_MMCI] = 0x1c050000, |
147 | [VE_KMI0] = 0x1c060000, |
148 | [VE_KMI1] = 0x1c070000, |
149 | [VE_UART0] = 0x1c090000, |
150 | [VE_UART1] = 0x1c0a0000, |
151 | [VE_UART2] = 0x1c0b0000, |
152 | [VE_UART3] = 0x1c0c0000, |
153 | [VE_WDT] = 0x1c0f0000, |
154 | [VE_TIMER01] = 0x1c110000, |
155 | [VE_TIMER23] = 0x1c120000, |
156 | [VE_VIRTIO] = 0x1c130000, |
157 | [VE_SERIALDVI] = 0x1c160000, |
158 | [VE_RTC] = 0x1c170000, |
159 | [VE_COMPACTFLASH] = 0x1c1a0000, |
160 | [VE_CLCD] = 0x1c1f0000, |
161 | }; |
162 | |
163 | /* Structure defining the peculiarities of a specific daughterboard */ |
164 | |
165 | typedef struct VEDBoardInfo VEDBoardInfo; |
166 | |
167 | typedef struct { |
168 | MachineClass parent; |
169 | VEDBoardInfo *daughterboard; |
170 | } VexpressMachineClass; |
171 | |
172 | typedef struct { |
173 | MachineState parent; |
174 | bool secure; |
175 | bool virt; |
176 | } VexpressMachineState; |
177 | |
178 | #define TYPE_VEXPRESS_MACHINE "vexpress" |
179 | #define TYPE_VEXPRESS_A9_MACHINE MACHINE_TYPE_NAME("vexpress-a9") |
180 | #define TYPE_VEXPRESS_A15_MACHINE MACHINE_TYPE_NAME("vexpress-a15") |
181 | #define VEXPRESS_MACHINE(obj) \ |
182 | OBJECT_CHECK(VexpressMachineState, (obj), TYPE_VEXPRESS_MACHINE) |
183 | #define VEXPRESS_MACHINE_GET_CLASS(obj) \ |
184 | OBJECT_GET_CLASS(VexpressMachineClass, obj, TYPE_VEXPRESS_MACHINE) |
185 | #define VEXPRESS_MACHINE_CLASS(klass) \ |
186 | OBJECT_CLASS_CHECK(VexpressMachineClass, klass, TYPE_VEXPRESS_MACHINE) |
187 | |
188 | typedef void DBoardInitFn(const VexpressMachineState *machine, |
189 | ram_addr_t ram_size, |
190 | const char *cpu_type, |
191 | qemu_irq *pic); |
192 | |
193 | struct VEDBoardInfo { |
194 | struct arm_boot_info bootinfo; |
195 | const hwaddr *motherboard_map; |
196 | hwaddr loader_start; |
197 | const hwaddr gic_cpu_if_addr; |
198 | uint32_t proc_id; |
199 | uint32_t num_voltage_sensors; |
200 | const uint32_t *voltages; |
201 | uint32_t num_clocks; |
202 | const uint32_t *clocks; |
203 | DBoardInitFn *init; |
204 | }; |
205 | |
206 | static void init_cpus(MachineState *ms, const char *cpu_type, |
207 | const char *privdev, hwaddr periphbase, |
208 | qemu_irq *pic, bool secure, bool virt) |
209 | { |
210 | DeviceState *dev; |
211 | SysBusDevice *busdev; |
212 | int n; |
213 | unsigned int smp_cpus = ms->smp.cpus; |
214 | |
215 | /* Create the actual CPUs */ |
216 | for (n = 0; n < smp_cpus; n++) { |
217 | Object *cpuobj = object_new(cpu_type); |
218 | |
219 | if (!secure) { |
220 | object_property_set_bool(cpuobj, false, "has_el3" , NULL); |
221 | } |
222 | if (!virt) { |
223 | if (object_property_find(cpuobj, "has_el2" , NULL)) { |
224 | object_property_set_bool(cpuobj, false, "has_el2" , NULL); |
225 | } |
226 | } |
227 | |
228 | if (object_property_find(cpuobj, "reset-cbar" , NULL)) { |
229 | object_property_set_int(cpuobj, periphbase, |
230 | "reset-cbar" , &error_abort); |
231 | } |
232 | object_property_set_bool(cpuobj, true, "realized" , &error_fatal); |
233 | } |
234 | |
235 | /* Create the private peripheral devices (including the GIC); |
236 | * this must happen after the CPUs are created because a15mpcore_priv |
237 | * wires itself up to the CPU's generic_timer gpio out lines. |
238 | */ |
239 | dev = qdev_create(NULL, privdev); |
240 | qdev_prop_set_uint32(dev, "num-cpu" , smp_cpus); |
241 | qdev_init_nofail(dev); |
242 | busdev = SYS_BUS_DEVICE(dev); |
243 | sysbus_mmio_map(busdev, 0, periphbase); |
244 | |
245 | /* Interrupts [42:0] are from the motherboard; |
246 | * [47:43] are reserved; [63:48] are daughterboard |
247 | * peripherals. Note that some documentation numbers |
248 | * external interrupts starting from 32 (because there |
249 | * are internal interrupts 0..31). |
250 | */ |
251 | for (n = 0; n < 64; n++) { |
252 | pic[n] = qdev_get_gpio_in(dev, n); |
253 | } |
254 | |
255 | /* Connect the CPUs to the GIC */ |
256 | for (n = 0; n < smp_cpus; n++) { |
257 | DeviceState *cpudev = DEVICE(qemu_get_cpu(n)); |
258 | |
259 | sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); |
260 | sysbus_connect_irq(busdev, n + smp_cpus, |
261 | qdev_get_gpio_in(cpudev, ARM_CPU_FIQ)); |
262 | sysbus_connect_irq(busdev, n + 2 * smp_cpus, |
263 | qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ)); |
264 | sysbus_connect_irq(busdev, n + 3 * smp_cpus, |
265 | qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ)); |
266 | } |
267 | } |
268 | |
269 | static void a9_daughterboard_init(const VexpressMachineState *vms, |
270 | ram_addr_t ram_size, |
271 | const char *cpu_type, |
272 | qemu_irq *pic) |
273 | { |
274 | MachineState *machine = MACHINE(vms); |
275 | MemoryRegion *sysmem = get_system_memory(); |
276 | MemoryRegion *ram = g_new(MemoryRegion, 1); |
277 | MemoryRegion *lowram = g_new(MemoryRegion, 1); |
278 | ram_addr_t low_ram_size; |
279 | |
280 | if (ram_size > 0x40000000) { |
281 | /* 1GB is the maximum the address space permits */ |
282 | error_report("vexpress-a9: cannot model more than 1GB RAM" ); |
283 | exit(1); |
284 | } |
285 | |
286 | memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem" , |
287 | ram_size); |
288 | low_ram_size = ram_size; |
289 | if (low_ram_size > 0x4000000) { |
290 | low_ram_size = 0x4000000; |
291 | } |
292 | /* RAM is from 0x60000000 upwards. The bottom 64MB of the |
293 | * address space should in theory be remappable to various |
294 | * things including ROM or RAM; we always map the RAM there. |
295 | */ |
296 | memory_region_init_alias(lowram, NULL, "vexpress.lowmem" , ram, 0, low_ram_size); |
297 | memory_region_add_subregion(sysmem, 0x0, lowram); |
298 | memory_region_add_subregion(sysmem, 0x60000000, ram); |
299 | |
300 | /* 0x1e000000 A9MPCore (SCU) private memory region */ |
301 | init_cpus(machine, cpu_type, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, |
302 | vms->secure, vms->virt); |
303 | |
304 | /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ |
305 | |
306 | /* 0x10020000 PL111 CLCD (daughterboard) */ |
307 | sysbus_create_simple("pl111" , 0x10020000, pic[44]); |
308 | |
309 | /* 0x10060000 AXI RAM */ |
310 | /* 0x100e0000 PL341 Dynamic Memory Controller */ |
311 | /* 0x100e1000 PL354 Static Memory Controller */ |
312 | /* 0x100e2000 System Configuration Controller */ |
313 | |
314 | sysbus_create_simple("sp804" , 0x100e4000, pic[48]); |
315 | /* 0x100e5000 SP805 Watchdog module */ |
316 | /* 0x100e6000 BP147 TrustZone Protection Controller */ |
317 | /* 0x100e9000 PL301 'Fast' AXI matrix */ |
318 | /* 0x100ea000 PL301 'Slow' AXI matrix */ |
319 | /* 0x100ec000 TrustZone Address Space Controller */ |
320 | /* 0x10200000 CoreSight debug APB */ |
321 | /* 0x1e00a000 PL310 L2 Cache Controller */ |
322 | sysbus_create_varargs("l2x0" , 0x1e00a000, NULL); |
323 | } |
324 | |
325 | /* Voltage values for SYS_CFG_VOLT daughterboard registers; |
326 | * values are in microvolts. |
327 | */ |
328 | static const uint32_t a9_voltages[] = { |
329 | 1000000, /* VD10 : 1.0V : SoC internal logic voltage */ |
330 | 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */ |
331 | 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */ |
332 | 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */ |
333 | 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */ |
334 | 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ |
335 | }; |
336 | |
337 | /* Reset values for daughterboard oscillators (in Hz) */ |
338 | static const uint32_t a9_clocks[] = { |
339 | 45000000, /* AMBA AXI ACLK: 45MHz */ |
340 | 23750000, /* daughterboard CLCD clock: 23.75MHz */ |
341 | 66670000, /* Test chip reference clock: 66.67MHz */ |
342 | }; |
343 | |
344 | static VEDBoardInfo a9_daughterboard = { |
345 | .motherboard_map = motherboard_legacy_map, |
346 | .loader_start = 0x60000000, |
347 | .gic_cpu_if_addr = 0x1e000100, |
348 | .proc_id = 0x0c000191, |
349 | .num_voltage_sensors = ARRAY_SIZE(a9_voltages), |
350 | .voltages = a9_voltages, |
351 | .num_clocks = ARRAY_SIZE(a9_clocks), |
352 | .clocks = a9_clocks, |
353 | .init = a9_daughterboard_init, |
354 | }; |
355 | |
356 | static void a15_daughterboard_init(const VexpressMachineState *vms, |
357 | ram_addr_t ram_size, |
358 | const char *cpu_type, |
359 | qemu_irq *pic) |
360 | { |
361 | MachineState *machine = MACHINE(vms); |
362 | MemoryRegion *sysmem = get_system_memory(); |
363 | MemoryRegion *ram = g_new(MemoryRegion, 1); |
364 | MemoryRegion *sram = g_new(MemoryRegion, 1); |
365 | |
366 | { |
367 | /* We have to use a separate 64 bit variable here to avoid the gcc |
368 | * "comparison is always false due to limited range of data type" |
369 | * warning if we are on a host where ram_addr_t is 32 bits. |
370 | */ |
371 | uint64_t rsz = ram_size; |
372 | if (rsz > (30ULL * 1024 * 1024 * 1024)) { |
373 | error_report("vexpress-a15: cannot model more than 30GB RAM" ); |
374 | exit(1); |
375 | } |
376 | } |
377 | |
378 | memory_region_allocate_system_memory(ram, NULL, "vexpress.highmem" , |
379 | ram_size); |
380 | /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */ |
381 | memory_region_add_subregion(sysmem, 0x80000000, ram); |
382 | |
383 | /* 0x2c000000 A15MPCore private memory region (GIC) */ |
384 | init_cpus(machine, cpu_type, TYPE_A15MPCORE_PRIV, |
385 | 0x2c000000, pic, vms->secure, vms->virt); |
386 | |
387 | /* A15 daughterboard peripherals: */ |
388 | |
389 | /* 0x20000000: CoreSight interfaces: not modelled */ |
390 | /* 0x2a000000: PL301 AXI interconnect: not modelled */ |
391 | /* 0x2a420000: SCC: not modelled */ |
392 | /* 0x2a430000: system counter: not modelled */ |
393 | /* 0x2b000000: HDLCD controller: not modelled */ |
394 | /* 0x2b060000: SP805 watchdog: not modelled */ |
395 | /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ |
396 | /* 0x2e000000: system SRAM */ |
397 | memory_region_init_ram(sram, NULL, "vexpress.a15sram" , 0x10000, |
398 | &error_fatal); |
399 | memory_region_add_subregion(sysmem, 0x2e000000, sram); |
400 | |
401 | /* 0x7ffb0000: DMA330 DMA controller: not modelled */ |
402 | /* 0x7ffd0000: PL354 static memory controller: not modelled */ |
403 | } |
404 | |
405 | static const uint32_t a15_voltages[] = { |
406 | 900000, /* Vcore: 0.9V : CPU core voltage */ |
407 | }; |
408 | |
409 | static const uint32_t a15_clocks[] = { |
410 | 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */ |
411 | 0, /* OSCCLK1: reserved */ |
412 | 0, /* OSCCLK2: reserved */ |
413 | 0, /* OSCCLK3: reserved */ |
414 | 40000000, /* OSCCLK4: 40MHz : external AXI master clock */ |
415 | 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */ |
416 | 50000000, /* OSCCLK6: 50MHz : static memory controller clock */ |
417 | 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */ |
418 | 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */ |
419 | }; |
420 | |
421 | static VEDBoardInfo a15_daughterboard = { |
422 | .motherboard_map = motherboard_aseries_map, |
423 | .loader_start = 0x80000000, |
424 | .gic_cpu_if_addr = 0x2c002000, |
425 | .proc_id = 0x14000237, |
426 | .num_voltage_sensors = ARRAY_SIZE(a15_voltages), |
427 | .voltages = a15_voltages, |
428 | .num_clocks = ARRAY_SIZE(a15_clocks), |
429 | .clocks = a15_clocks, |
430 | .init = a15_daughterboard_init, |
431 | }; |
432 | |
433 | static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, |
434 | hwaddr addr, hwaddr size, uint32_t intc, |
435 | int irq) |
436 | { |
437 | /* Add a virtio_mmio node to the device tree blob: |
438 | * virtio_mmio@ADDRESS { |
439 | * compatible = "virtio,mmio"; |
440 | * reg = <ADDRESS, SIZE>; |
441 | * interrupt-parent = <&intc>; |
442 | * interrupts = <0, irq, 1>; |
443 | * } |
444 | * (Note that the format of the interrupts property is dependent on the |
445 | * interrupt controller that interrupt-parent points to; these are for |
446 | * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.) |
447 | */ |
448 | int rc; |
449 | char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr); |
450 | |
451 | rc = qemu_fdt_add_subnode(fdt, nodename); |
452 | rc |= qemu_fdt_setprop_string(fdt, nodename, |
453 | "compatible" , "virtio,mmio" ); |
454 | rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg" , |
455 | acells, addr, scells, size); |
456 | qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent" , intc); |
457 | qemu_fdt_setprop_cells(fdt, nodename, "interrupts" , 0, irq, 1); |
458 | qemu_fdt_setprop(fdt, nodename, "dma-coherent" , NULL, 0); |
459 | g_free(nodename); |
460 | if (rc) { |
461 | return -1; |
462 | } |
463 | return 0; |
464 | } |
465 | |
466 | static uint32_t find_int_controller(void *fdt) |
467 | { |
468 | /* Find the FDT node corresponding to the interrupt controller |
469 | * for virtio-mmio devices. We do this by scanning the fdt for |
470 | * a node with the right compatibility, since we know there is |
471 | * only one GIC on a vexpress board. |
472 | * We return the phandle of the node, or 0 if none was found. |
473 | */ |
474 | const char *compat = "arm,cortex-a9-gic" ; |
475 | int offset; |
476 | |
477 | offset = fdt_node_offset_by_compatible(fdt, -1, compat); |
478 | if (offset >= 0) { |
479 | return fdt_get_phandle(fdt, offset); |
480 | } |
481 | return 0; |
482 | } |
483 | |
484 | static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) |
485 | { |
486 | uint32_t acells, scells, intc; |
487 | const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; |
488 | |
489 | acells = qemu_fdt_getprop_cell(fdt, "/" , "#address-cells" , |
490 | NULL, &error_fatal); |
491 | scells = qemu_fdt_getprop_cell(fdt, "/" , "#size-cells" , |
492 | NULL, &error_fatal); |
493 | intc = find_int_controller(fdt); |
494 | if (!intc) { |
495 | /* Not fatal, we just won't provide virtio. This will |
496 | * happen with older device tree blobs. |
497 | */ |
498 | warn_report("couldn't find interrupt controller in " |
499 | "dtb; will not include virtio-mmio devices in the dtb" ); |
500 | } else { |
501 | int i; |
502 | const hwaddr *map = daughterboard->motherboard_map; |
503 | |
504 | /* We iterate backwards here because adding nodes |
505 | * to the dtb puts them in last-first. |
506 | */ |
507 | for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) { |
508 | add_virtio_mmio_node(fdt, acells, scells, |
509 | map[VE_VIRTIO] + 0x200 * i, |
510 | 0x200, intc, 40 + i); |
511 | } |
512 | } |
513 | } |
514 | |
515 | |
516 | /* Open code a private version of pflash registration since we |
517 | * need to set non-default device width for VExpress platform. |
518 | */ |
519 | static PFlashCFI01 *ve_pflash_cfi01_register(hwaddr base, const char *name, |
520 | DriveInfo *di) |
521 | { |
522 | DeviceState *dev = qdev_create(NULL, TYPE_PFLASH_CFI01); |
523 | |
524 | if (di) { |
525 | qdev_prop_set_drive(dev, "drive" , blk_by_legacy_dinfo(di), |
526 | &error_abort); |
527 | } |
528 | |
529 | qdev_prop_set_uint32(dev, "num-blocks" , |
530 | VEXPRESS_FLASH_SIZE / VEXPRESS_FLASH_SECT_SIZE); |
531 | qdev_prop_set_uint64(dev, "sector-length" , VEXPRESS_FLASH_SECT_SIZE); |
532 | qdev_prop_set_uint8(dev, "width" , 4); |
533 | qdev_prop_set_uint8(dev, "device-width" , 2); |
534 | qdev_prop_set_bit(dev, "big-endian" , false); |
535 | qdev_prop_set_uint16(dev, "id0" , 0x89); |
536 | qdev_prop_set_uint16(dev, "id1" , 0x18); |
537 | qdev_prop_set_uint16(dev, "id2" , 0x00); |
538 | qdev_prop_set_uint16(dev, "id3" , 0x00); |
539 | qdev_prop_set_string(dev, "name" , name); |
540 | qdev_init_nofail(dev); |
541 | |
542 | sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); |
543 | return PFLASH_CFI01(dev); |
544 | } |
545 | |
546 | static void vexpress_common_init(MachineState *machine) |
547 | { |
548 | VexpressMachineState *vms = VEXPRESS_MACHINE(machine); |
549 | VexpressMachineClass *vmc = VEXPRESS_MACHINE_GET_CLASS(machine); |
550 | VEDBoardInfo *daughterboard = vmc->daughterboard; |
551 | DeviceState *dev, *sysctl, *pl041; |
552 | qemu_irq pic[64]; |
553 | uint32_t sys_id; |
554 | DriveInfo *dinfo; |
555 | PFlashCFI01 *pflash0; |
556 | I2CBus *i2c; |
557 | ram_addr_t vram_size, sram_size; |
558 | MemoryRegion *sysmem = get_system_memory(); |
559 | MemoryRegion *vram = g_new(MemoryRegion, 1); |
560 | MemoryRegion *sram = g_new(MemoryRegion, 1); |
561 | MemoryRegion *flashalias = g_new(MemoryRegion, 1); |
562 | MemoryRegion *flash0mem; |
563 | const hwaddr *map = daughterboard->motherboard_map; |
564 | int i; |
565 | |
566 | daughterboard->init(vms, machine->ram_size, machine->cpu_type, pic); |
567 | |
568 | /* |
569 | * If a bios file was provided, attempt to map it into memory |
570 | */ |
571 | if (bios_name) { |
572 | char *fn; |
573 | int image_size; |
574 | |
575 | if (drive_get(IF_PFLASH, 0, 0)) { |
576 | error_report("The contents of the first flash device may be " |
577 | "specified with -bios or with -drive if=pflash... " |
578 | "but you cannot use both options at once" ); |
579 | exit(1); |
580 | } |
581 | fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); |
582 | if (!fn) { |
583 | error_report("Could not find ROM image '%s'" , bios_name); |
584 | exit(1); |
585 | } |
586 | image_size = load_image_targphys(fn, map[VE_NORFLASH0], |
587 | VEXPRESS_FLASH_SIZE); |
588 | g_free(fn); |
589 | if (image_size < 0) { |
590 | error_report("Could not load ROM image '%s'" , bios_name); |
591 | exit(1); |
592 | } |
593 | } |
594 | |
595 | /* Motherboard peripherals: the wiring is the same but the |
596 | * addresses vary between the legacy and A-Series memory maps. |
597 | */ |
598 | |
599 | sys_id = 0x1190f500; |
600 | |
601 | sysctl = qdev_create(NULL, "realview_sysctl" ); |
602 | qdev_prop_set_uint32(sysctl, "sys_id" , sys_id); |
603 | qdev_prop_set_uint32(sysctl, "proc_id" , daughterboard->proc_id); |
604 | qdev_prop_set_uint32(sysctl, "len-db-voltage" , |
605 | daughterboard->num_voltage_sensors); |
606 | for (i = 0; i < daughterboard->num_voltage_sensors; i++) { |
607 | char *propname = g_strdup_printf("db-voltage[%d]" , i); |
608 | qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); |
609 | g_free(propname); |
610 | } |
611 | qdev_prop_set_uint32(sysctl, "len-db-clock" , |
612 | daughterboard->num_clocks); |
613 | for (i = 0; i < daughterboard->num_clocks; i++) { |
614 | char *propname = g_strdup_printf("db-clock[%d]" , i); |
615 | qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); |
616 | g_free(propname); |
617 | } |
618 | qdev_init_nofail(sysctl); |
619 | sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]); |
620 | |
621 | /* VE_SP810: not modelled */ |
622 | /* VE_SERIALPCI: not modelled */ |
623 | |
624 | pl041 = qdev_create(NULL, "pl041" ); |
625 | qdev_prop_set_uint32(pl041, "nc_fifo_depth" , 512); |
626 | qdev_init_nofail(pl041); |
627 | sysbus_mmio_map(SYS_BUS_DEVICE(pl041), 0, map[VE_PL041]); |
628 | sysbus_connect_irq(SYS_BUS_DEVICE(pl041), 0, pic[11]); |
629 | |
630 | dev = sysbus_create_varargs("pl181" , map[VE_MMCI], pic[9], pic[10], NULL); |
631 | /* Wire up MMC card detect and read-only signals */ |
632 | qdev_connect_gpio_out(dev, 0, |
633 | qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT)); |
634 | qdev_connect_gpio_out(dev, 1, |
635 | qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN)); |
636 | |
637 | sysbus_create_simple("pl050_keyboard" , map[VE_KMI0], pic[12]); |
638 | sysbus_create_simple("pl050_mouse" , map[VE_KMI1], pic[13]); |
639 | |
640 | pl011_create(map[VE_UART0], pic[5], serial_hd(0)); |
641 | pl011_create(map[VE_UART1], pic[6], serial_hd(1)); |
642 | pl011_create(map[VE_UART2], pic[7], serial_hd(2)); |
643 | pl011_create(map[VE_UART3], pic[8], serial_hd(3)); |
644 | |
645 | sysbus_create_simple("sp804" , map[VE_TIMER01], pic[2]); |
646 | sysbus_create_simple("sp804" , map[VE_TIMER23], pic[3]); |
647 | |
648 | dev = sysbus_create_simple("versatile_i2c" , map[VE_SERIALDVI], NULL); |
649 | i2c = (I2CBus *)qdev_get_child_bus(dev, "i2c" ); |
650 | i2c_create_slave(i2c, "sii9022" , 0x39); |
651 | |
652 | sysbus_create_simple("pl031" , map[VE_RTC], pic[4]); /* RTC */ |
653 | |
654 | /* VE_COMPACTFLASH: not modelled */ |
655 | |
656 | sysbus_create_simple("pl111" , map[VE_CLCD], pic[14]); |
657 | |
658 | dinfo = drive_get_next(IF_PFLASH); |
659 | pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0" , |
660 | dinfo); |
661 | if (!pflash0) { |
662 | error_report("vexpress: error registering flash 0" ); |
663 | exit(1); |
664 | } |
665 | |
666 | if (map[VE_NORFLASHALIAS] != -1) { |
667 | /* Map flash 0 as an alias into low memory */ |
668 | flash0mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pflash0), 0); |
669 | memory_region_init_alias(flashalias, NULL, "vexpress.flashalias" , |
670 | flash0mem, 0, VEXPRESS_FLASH_SIZE); |
671 | memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias); |
672 | } |
673 | |
674 | dinfo = drive_get_next(IF_PFLASH); |
675 | if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1" , |
676 | dinfo)) { |
677 | error_report("vexpress: error registering flash 1" ); |
678 | exit(1); |
679 | } |
680 | |
681 | sram_size = 0x2000000; |
682 | memory_region_init_ram(sram, NULL, "vexpress.sram" , sram_size, |
683 | &error_fatal); |
684 | memory_region_add_subregion(sysmem, map[VE_SRAM], sram); |
685 | |
686 | vram_size = 0x800000; |
687 | memory_region_init_ram(vram, NULL, "vexpress.vram" , vram_size, |
688 | &error_fatal); |
689 | memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); |
690 | |
691 | /* 0x4e000000 LAN9118 Ethernet */ |
692 | if (nd_table[0].used) { |
693 | lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]); |
694 | } |
695 | |
696 | /* VE_USB: not modelled */ |
697 | |
698 | /* VE_DAPROM: not modelled */ |
699 | |
700 | /* Create mmio transports, so the user can create virtio backends |
701 | * (which will be automatically plugged in to the transports). If |
702 | * no backend is created the transport will just sit harmlessly idle. |
703 | */ |
704 | for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) { |
705 | sysbus_create_simple("virtio-mmio" , map[VE_VIRTIO] + 0x200 * i, |
706 | pic[40 + i]); |
707 | } |
708 | |
709 | daughterboard->bootinfo.ram_size = machine->ram_size; |
710 | daughterboard->bootinfo.nb_cpus = machine->smp.cpus; |
711 | daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID; |
712 | daughterboard->bootinfo.loader_start = daughterboard->loader_start; |
713 | daughterboard->bootinfo.smp_loader_start = map[VE_SRAM]; |
714 | daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; |
715 | daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; |
716 | daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb; |
717 | /* When booting Linux we should be in secure state if the CPU has one. */ |
718 | daughterboard->bootinfo.secure_boot = vms->secure; |
719 | arm_load_kernel(ARM_CPU(first_cpu), machine, &daughterboard->bootinfo); |
720 | } |
721 | |
722 | static bool vexpress_get_secure(Object *obj, Error **errp) |
723 | { |
724 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
725 | |
726 | return vms->secure; |
727 | } |
728 | |
729 | static void vexpress_set_secure(Object *obj, bool value, Error **errp) |
730 | { |
731 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
732 | |
733 | vms->secure = value; |
734 | } |
735 | |
736 | static bool vexpress_get_virt(Object *obj, Error **errp) |
737 | { |
738 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
739 | |
740 | return vms->virt; |
741 | } |
742 | |
743 | static void vexpress_set_virt(Object *obj, bool value, Error **errp) |
744 | { |
745 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
746 | |
747 | vms->virt = value; |
748 | } |
749 | |
750 | static void vexpress_instance_init(Object *obj) |
751 | { |
752 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
753 | |
754 | /* EL3 is enabled by default on vexpress */ |
755 | vms->secure = true; |
756 | object_property_add_bool(obj, "secure" , vexpress_get_secure, |
757 | vexpress_set_secure, NULL); |
758 | object_property_set_description(obj, "secure" , |
759 | "Set on/off to enable/disable the ARM " |
760 | "Security Extensions (TrustZone)" , |
761 | NULL); |
762 | } |
763 | |
764 | static void vexpress_a15_instance_init(Object *obj) |
765 | { |
766 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
767 | |
768 | /* |
769 | * For the vexpress-a15, EL2 is by default enabled if EL3 is, |
770 | * but can also be specifically set to on or off. |
771 | */ |
772 | vms->virt = true; |
773 | object_property_add_bool(obj, "virtualization" , vexpress_get_virt, |
774 | vexpress_set_virt, NULL); |
775 | object_property_set_description(obj, "virtualization" , |
776 | "Set on/off to enable/disable the ARM " |
777 | "Virtualization Extensions " |
778 | "(defaults to same as 'secure')" , |
779 | NULL); |
780 | } |
781 | |
782 | static void vexpress_a9_instance_init(Object *obj) |
783 | { |
784 | VexpressMachineState *vms = VEXPRESS_MACHINE(obj); |
785 | |
786 | /* The A9 doesn't have the virt extensions */ |
787 | vms->virt = false; |
788 | } |
789 | |
790 | static void vexpress_class_init(ObjectClass *oc, void *data) |
791 | { |
792 | MachineClass *mc = MACHINE_CLASS(oc); |
793 | |
794 | mc->desc = "ARM Versatile Express" ; |
795 | mc->init = vexpress_common_init; |
796 | mc->max_cpus = 4; |
797 | mc->ignore_memory_transaction_failures = true; |
798 | } |
799 | |
800 | static void vexpress_a9_class_init(ObjectClass *oc, void *data) |
801 | { |
802 | MachineClass *mc = MACHINE_CLASS(oc); |
803 | VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); |
804 | |
805 | mc->desc = "ARM Versatile Express for Cortex-A9" ; |
806 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a9" ); |
807 | |
808 | vmc->daughterboard = &a9_daughterboard; |
809 | } |
810 | |
811 | static void vexpress_a15_class_init(ObjectClass *oc, void *data) |
812 | { |
813 | MachineClass *mc = MACHINE_CLASS(oc); |
814 | VexpressMachineClass *vmc = VEXPRESS_MACHINE_CLASS(oc); |
815 | |
816 | mc->desc = "ARM Versatile Express for Cortex-A15" ; |
817 | mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15" ); |
818 | |
819 | vmc->daughterboard = &a15_daughterboard; |
820 | } |
821 | |
822 | static const TypeInfo vexpress_info = { |
823 | .name = TYPE_VEXPRESS_MACHINE, |
824 | .parent = TYPE_MACHINE, |
825 | .abstract = true, |
826 | .instance_size = sizeof(VexpressMachineState), |
827 | .instance_init = vexpress_instance_init, |
828 | .class_size = sizeof(VexpressMachineClass), |
829 | .class_init = vexpress_class_init, |
830 | }; |
831 | |
832 | static const TypeInfo vexpress_a9_info = { |
833 | .name = TYPE_VEXPRESS_A9_MACHINE, |
834 | .parent = TYPE_VEXPRESS_MACHINE, |
835 | .class_init = vexpress_a9_class_init, |
836 | .instance_init = vexpress_a9_instance_init, |
837 | }; |
838 | |
839 | static const TypeInfo vexpress_a15_info = { |
840 | .name = TYPE_VEXPRESS_A15_MACHINE, |
841 | .parent = TYPE_VEXPRESS_MACHINE, |
842 | .class_init = vexpress_a15_class_init, |
843 | .instance_init = vexpress_a15_instance_init, |
844 | }; |
845 | |
846 | static void vexpress_machine_init(void) |
847 | { |
848 | type_register_static(&vexpress_info); |
849 | type_register_static(&vexpress_a9_info); |
850 | type_register_static(&vexpress_a15_info); |
851 | } |
852 | |
853 | type_init(vexpress_machine_init); |
854 | |