File: | hw/arm/vexpress.c |
Location: | line 346, column 9 |
Description: | Function call argument is an uninitialized value |
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 "hw/sysbus.h" | |||
25 | #include "hw/arm/arm.h" | |||
26 | #include "hw/arm/primecell.h" | |||
27 | #include "hw/devices.h" | |||
28 | #include "net/net.h" | |||
29 | #include "sysemu/sysemu.h" | |||
30 | #include "hw/boards.h" | |||
31 | #include "exec/address-spaces.h" | |||
32 | #include "sysemu/blockdev.h" | |||
33 | #include "hw/block/flash.h" | |||
34 | #include "sysemu/device_tree.h" | |||
35 | #include <libfdt.h> | |||
36 | ||||
37 | #define VEXPRESS_BOARD_ID0x8e0 0x8e0 | |||
38 | #define VEXPRESS_FLASH_SIZE(64 * 1024 * 1024) (64 * 1024 * 1024) | |||
39 | #define VEXPRESS_FLASH_SECT_SIZE(256 * 1024) (256 * 1024) | |||
40 | ||||
41 | /* Number of virtio transports to create (0..8; limited by | |||
42 | * number of available IRQ lines). | |||
43 | */ | |||
44 | #define NUM_VIRTIO_TRANSPORTS4 4 | |||
45 | ||||
46 | /* Address maps for peripherals: | |||
47 | * the Versatile Express motherboard has two possible maps, | |||
48 | * the "legacy" one (used for A9) and the "Cortex-A Series" | |||
49 | * map (used for newer cores). | |||
50 | * Individual daughterboards can also have different maps for | |||
51 | * their peripherals. | |||
52 | */ | |||
53 | ||||
54 | enum { | |||
55 | VE_SYSREGS, | |||
56 | VE_SP810, | |||
57 | VE_SERIALPCI, | |||
58 | VE_PL041, | |||
59 | VE_MMCI, | |||
60 | VE_KMI0, | |||
61 | VE_KMI1, | |||
62 | VE_UART0, | |||
63 | VE_UART1, | |||
64 | VE_UART2, | |||
65 | VE_UART3, | |||
66 | VE_WDT, | |||
67 | VE_TIMER01, | |||
68 | VE_TIMER23, | |||
69 | VE_SERIALDVI, | |||
70 | VE_RTC, | |||
71 | VE_COMPACTFLASH, | |||
72 | VE_CLCD, | |||
73 | VE_NORFLASH0, | |||
74 | VE_NORFLASH1, | |||
75 | VE_NORFLASHALIAS, | |||
76 | VE_SRAM, | |||
77 | VE_VIDEORAM, | |||
78 | VE_ETHERNET, | |||
79 | VE_USB, | |||
80 | VE_DAPROM, | |||
81 | VE_VIRTIO, | |||
82 | }; | |||
83 | ||||
84 | static hwaddr motherboard_legacy_map[] = { | |||
85 | /* CS7: 0x10000000 .. 0x10020000 */ | |||
86 | [VE_SYSREGS] = 0x10000000, | |||
87 | [VE_SP810] = 0x10001000, | |||
88 | [VE_SERIALPCI] = 0x10002000, | |||
89 | [VE_PL041] = 0x10004000, | |||
90 | [VE_MMCI] = 0x10005000, | |||
91 | [VE_KMI0] = 0x10006000, | |||
92 | [VE_KMI1] = 0x10007000, | |||
93 | [VE_UART0] = 0x10009000, | |||
94 | [VE_UART1] = 0x1000a000, | |||
95 | [VE_UART2] = 0x1000b000, | |||
96 | [VE_UART3] = 0x1000c000, | |||
97 | [VE_WDT] = 0x1000f000, | |||
98 | [VE_TIMER01] = 0x10011000, | |||
99 | [VE_TIMER23] = 0x10012000, | |||
100 | [VE_VIRTIO] = 0x10013000, | |||
101 | [VE_SERIALDVI] = 0x10016000, | |||
102 | [VE_RTC] = 0x10017000, | |||
103 | [VE_COMPACTFLASH] = 0x1001a000, | |||
104 | [VE_CLCD] = 0x1001f000, | |||
105 | /* CS0: 0x40000000 .. 0x44000000 */ | |||
106 | [VE_NORFLASH0] = 0x40000000, | |||
107 | /* CS1: 0x44000000 .. 0x48000000 */ | |||
108 | [VE_NORFLASH1] = 0x44000000, | |||
109 | /* CS2: 0x48000000 .. 0x4a000000 */ | |||
110 | [VE_SRAM] = 0x48000000, | |||
111 | /* CS3: 0x4c000000 .. 0x50000000 */ | |||
112 | [VE_VIDEORAM] = 0x4c000000, | |||
113 | [VE_ETHERNET] = 0x4e000000, | |||
114 | [VE_USB] = 0x4f000000, | |||
115 | [VE_NORFLASHALIAS] = -1, /* not present */ | |||
116 | }; | |||
117 | ||||
118 | static hwaddr motherboard_aseries_map[] = { | |||
119 | [VE_NORFLASHALIAS] = 0, | |||
120 | /* CS0: 0x08000000 .. 0x0c000000 */ | |||
121 | [VE_NORFLASH0] = 0x08000000, | |||
122 | /* CS4: 0x0c000000 .. 0x10000000 */ | |||
123 | [VE_NORFLASH1] = 0x0c000000, | |||
124 | /* CS5: 0x10000000 .. 0x14000000 */ | |||
125 | /* CS1: 0x14000000 .. 0x18000000 */ | |||
126 | [VE_SRAM] = 0x14000000, | |||
127 | /* CS2: 0x18000000 .. 0x1c000000 */ | |||
128 | [VE_VIDEORAM] = 0x18000000, | |||
129 | [VE_ETHERNET] = 0x1a000000, | |||
130 | [VE_USB] = 0x1b000000, | |||
131 | /* CS3: 0x1c000000 .. 0x20000000 */ | |||
132 | [VE_DAPROM] = 0x1c000000, | |||
133 | [VE_SYSREGS] = 0x1c010000, | |||
134 | [VE_SP810] = 0x1c020000, | |||
135 | [VE_SERIALPCI] = 0x1c030000, | |||
136 | [VE_PL041] = 0x1c040000, | |||
137 | [VE_MMCI] = 0x1c050000, | |||
138 | [VE_KMI0] = 0x1c060000, | |||
139 | [VE_KMI1] = 0x1c070000, | |||
140 | [VE_UART0] = 0x1c090000, | |||
141 | [VE_UART1] = 0x1c0a0000, | |||
142 | [VE_UART2] = 0x1c0b0000, | |||
143 | [VE_UART3] = 0x1c0c0000, | |||
144 | [VE_WDT] = 0x1c0f0000, | |||
145 | [VE_TIMER01] = 0x1c110000, | |||
146 | [VE_TIMER23] = 0x1c120000, | |||
147 | [VE_VIRTIO] = 0x1c130000, | |||
148 | [VE_SERIALDVI] = 0x1c160000, | |||
149 | [VE_RTC] = 0x1c170000, | |||
150 | [VE_COMPACTFLASH] = 0x1c1a0000, | |||
151 | [VE_CLCD] = 0x1c1f0000, | |||
152 | }; | |||
153 | ||||
154 | /* Structure defining the peculiarities of a specific daughterboard */ | |||
155 | ||||
156 | typedef struct VEDBoardInfo VEDBoardInfo; | |||
157 | ||||
158 | typedef void DBoardInitFn(const VEDBoardInfo *daughterboard, | |||
159 | ram_addr_t ram_size, | |||
160 | const char *cpu_model, | |||
161 | qemu_irq *pic); | |||
162 | ||||
163 | struct VEDBoardInfo { | |||
164 | struct arm_boot_info bootinfo; | |||
165 | const hwaddr *motherboard_map; | |||
166 | hwaddr loader_start; | |||
167 | const hwaddr gic_cpu_if_addr; | |||
168 | uint32_t proc_id; | |||
169 | uint32_t num_voltage_sensors; | |||
170 | const uint32_t *voltages; | |||
171 | uint32_t num_clocks; | |||
172 | const uint32_t *clocks; | |||
173 | DBoardInitFn *init; | |||
174 | }; | |||
175 | ||||
176 | static void a9_daughterboard_init(const VEDBoardInfo *daughterboard, | |||
177 | ram_addr_t ram_size, | |||
178 | const char *cpu_model, | |||
179 | qemu_irq *pic) | |||
180 | { | |||
181 | MemoryRegion *sysmem = get_system_memory(); | |||
182 | MemoryRegion *ram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
183 | MemoryRegion *lowram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
184 | DeviceState *dev; | |||
185 | SysBusDevice *busdev; | |||
186 | int n; | |||
187 | qemu_irq cpu_irq[4]; | |||
188 | ram_addr_t low_ram_size; | |||
189 | ||||
190 | if (!cpu_model) { | |||
191 | cpu_model = "cortex-a9"; | |||
192 | } | |||
193 | ||||
194 | for (n = 0; n < smp_cpus; n++) { | |||
195 | ARMCPU *cpu = cpu_arm_init(cpu_model); | |||
196 | if (!cpu) { | |||
197 | fprintf(stderrstderr, "Unable to find CPU definition\n"); | |||
198 | exit(1); | |||
199 | } | |||
200 | cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu)((DeviceState *)object_dynamic_cast_assert(((Object *)((cpu)) ), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 200, __func__)), ARM_CPU_IRQ0); | |||
201 | } | |||
202 | ||||
203 | if (ram_size > 0x40000000) { | |||
204 | /* 1GB is the maximum the address space permits */ | |||
205 | fprintf(stderrstderr, "vexpress-a9: cannot model more than 1GB RAM\n"); | |||
206 | exit(1); | |||
207 | } | |||
208 | ||||
209 | memory_region_init_ram(ram, NULL((void*)0), "vexpress.highmem", ram_size); | |||
210 | vmstate_register_ram_global(ram); | |||
211 | low_ram_size = ram_size; | |||
212 | if (low_ram_size > 0x4000000) { | |||
213 | low_ram_size = 0x4000000; | |||
214 | } | |||
215 | /* RAM is from 0x60000000 upwards. The bottom 64MB of the | |||
216 | * address space should in theory be remappable to various | |||
217 | * things including ROM or RAM; we always map the RAM there. | |||
218 | */ | |||
219 | memory_region_init_alias(lowram, NULL((void*)0), "vexpress.lowmem", ram, 0, low_ram_size); | |||
220 | memory_region_add_subregion(sysmem, 0x0, lowram); | |||
221 | memory_region_add_subregion(sysmem, 0x60000000, ram); | |||
222 | ||||
223 | /* 0x1e000000 A9MPCore (SCU) private memory region */ | |||
224 | dev = qdev_create(NULL((void*)0), "a9mpcore_priv"); | |||
225 | qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); | |||
226 | qdev_init_nofail(dev); | |||
227 | busdev = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 227, __func__)); | |||
228 | sysbus_mmio_map(busdev, 0, 0x1e000000); | |||
229 | for (n = 0; n < smp_cpus; n++) { | |||
230 | sysbus_connect_irq(busdev, n, cpu_irq[n]); | |||
231 | } | |||
232 | /* Interrupts [42:0] are from the motherboard; | |||
233 | * [47:43] are reserved; [63:48] are daughterboard | |||
234 | * peripherals. Note that some documentation numbers | |||
235 | * external interrupts starting from 32 (because the | |||
236 | * A9MP has internal interrupts 0..31). | |||
237 | */ | |||
238 | for (n = 0; n < 64; n++) { | |||
239 | pic[n] = qdev_get_gpio_in(dev, n); | |||
240 | } | |||
241 | ||||
242 | /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ | |||
243 | ||||
244 | /* 0x10020000 PL111 CLCD (daughterboard) */ | |||
245 | sysbus_create_simple("pl111", 0x10020000, pic[44]); | |||
246 | ||||
247 | /* 0x10060000 AXI RAM */ | |||
248 | /* 0x100e0000 PL341 Dynamic Memory Controller */ | |||
249 | /* 0x100e1000 PL354 Static Memory Controller */ | |||
250 | /* 0x100e2000 System Configuration Controller */ | |||
251 | ||||
252 | sysbus_create_simple("sp804", 0x100e4000, pic[48]); | |||
253 | /* 0x100e5000 SP805 Watchdog module */ | |||
254 | /* 0x100e6000 BP147 TrustZone Protection Controller */ | |||
255 | /* 0x100e9000 PL301 'Fast' AXI matrix */ | |||
256 | /* 0x100ea000 PL301 'Slow' AXI matrix */ | |||
257 | /* 0x100ec000 TrustZone Address Space Controller */ | |||
258 | /* 0x10200000 CoreSight debug APB */ | |||
259 | /* 0x1e00a000 PL310 L2 Cache Controller */ | |||
260 | sysbus_create_varargs("l2x0", 0x1e00a000, NULL((void*)0)); | |||
261 | } | |||
262 | ||||
263 | /* Voltage values for SYS_CFG_VOLT daughterboard registers; | |||
264 | * values are in microvolts. | |||
265 | */ | |||
266 | static const uint32_t a9_voltages[] = { | |||
267 | 1000000, /* VD10 : 1.0V : SoC internal logic voltage */ | |||
268 | 1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */ | |||
269 | 1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */ | |||
270 | 1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */ | |||
271 | 900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */ | |||
272 | 3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */ | |||
273 | }; | |||
274 | ||||
275 | /* Reset values for daughterboard oscillators (in Hz) */ | |||
276 | static const uint32_t a9_clocks[] = { | |||
277 | 45000000, /* AMBA AXI ACLK: 45MHz */ | |||
278 | 23750000, /* daughterboard CLCD clock: 23.75MHz */ | |||
279 | 66670000, /* Test chip reference clock: 66.67MHz */ | |||
280 | }; | |||
281 | ||||
282 | static VEDBoardInfo a9_daughterboard = { | |||
283 | .motherboard_map = motherboard_legacy_map, | |||
284 | .loader_start = 0x60000000, | |||
285 | .gic_cpu_if_addr = 0x1e000100, | |||
286 | .proc_id = 0x0c000191, | |||
287 | .num_voltage_sensors = ARRAY_SIZE(a9_voltages)(sizeof(a9_voltages) / sizeof((a9_voltages)[0])), | |||
288 | .voltages = a9_voltages, | |||
289 | .num_clocks = ARRAY_SIZE(a9_clocks)(sizeof(a9_clocks) / sizeof((a9_clocks)[0])), | |||
290 | .clocks = a9_clocks, | |||
291 | .init = a9_daughterboard_init, | |||
292 | }; | |||
293 | ||||
294 | static void a15_daughterboard_init(const VEDBoardInfo *daughterboard, | |||
295 | ram_addr_t ram_size, | |||
296 | const char *cpu_model, | |||
297 | qemu_irq *pic) | |||
298 | { | |||
299 | int n; | |||
300 | MemoryRegion *sysmem = get_system_memory(); | |||
301 | MemoryRegion *ram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
302 | MemoryRegion *sram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
303 | qemu_irq cpu_irq[4]; | |||
304 | DeviceState *dev; | |||
305 | SysBusDevice *busdev; | |||
306 | ||||
307 | if (!cpu_model) { | |||
| ||||
308 | cpu_model = "cortex-a15"; | |||
309 | } | |||
310 | ||||
311 | for (n = 0; n < smp_cpus; n++) { | |||
312 | ARMCPU *cpu; | |||
313 | ||||
314 | cpu = cpu_arm_init(cpu_model); | |||
315 | if (!cpu) { | |||
316 | fprintf(stderrstderr, "Unable to find CPU definition\n"); | |||
317 | exit(1); | |||
318 | } | |||
319 | cpu_irq[n] = qdev_get_gpio_in(DEVICE(cpu)((DeviceState *)object_dynamic_cast_assert(((Object *)((cpu)) ), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 319, __func__)), ARM_CPU_IRQ0); | |||
320 | } | |||
321 | ||||
322 | { | |||
323 | /* We have to use a separate 64 bit variable here to avoid the gcc | |||
324 | * "comparison is always false due to limited range of data type" | |||
325 | * warning if we are on a host where ram_addr_t is 32 bits. | |||
326 | */ | |||
327 | uint64_t rsz = ram_size; | |||
328 | if (rsz > (30ULL * 1024 * 1024 * 1024)) { | |||
329 | fprintf(stderrstderr, "vexpress-a15: cannot model more than 30GB RAM\n"); | |||
330 | exit(1); | |||
331 | } | |||
332 | } | |||
333 | ||||
334 | memory_region_init_ram(ram, NULL((void*)0), "vexpress.highmem", ram_size); | |||
335 | vmstate_register_ram_global(ram); | |||
336 | /* RAM is from 0x80000000 upwards; there is no low-memory alias for it. */ | |||
337 | memory_region_add_subregion(sysmem, 0x80000000, ram); | |||
338 | ||||
339 | /* 0x2c000000 A15MPCore private memory region (GIC) */ | |||
340 | dev = qdev_create(NULL((void*)0), "a15mpcore_priv"); | |||
341 | qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); | |||
342 | qdev_init_nofail(dev); | |||
343 | busdev = SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 343, __func__)); | |||
344 | sysbus_mmio_map(busdev, 0, 0x2c000000); | |||
345 | for (n = 0; n < smp_cpus; n++) { | |||
346 | sysbus_connect_irq(busdev, n, cpu_irq[n]); | |||
| ||||
347 | } | |||
348 | /* Interrupts [42:0] are from the motherboard; | |||
349 | * [47:43] are reserved; [63:48] are daughterboard | |||
350 | * peripherals. Note that some documentation numbers | |||
351 | * external interrupts starting from 32 (because there | |||
352 | * are internal interrupts 0..31). | |||
353 | */ | |||
354 | for (n = 0; n < 64; n++) { | |||
355 | pic[n] = qdev_get_gpio_in(dev, n); | |||
356 | } | |||
357 | ||||
358 | /* A15 daughterboard peripherals: */ | |||
359 | ||||
360 | /* 0x20000000: CoreSight interfaces: not modelled */ | |||
361 | /* 0x2a000000: PL301 AXI interconnect: not modelled */ | |||
362 | /* 0x2a420000: SCC: not modelled */ | |||
363 | /* 0x2a430000: system counter: not modelled */ | |||
364 | /* 0x2b000000: HDLCD controller: not modelled */ | |||
365 | /* 0x2b060000: SP805 watchdog: not modelled */ | |||
366 | /* 0x2b0a0000: PL341 dynamic memory controller: not modelled */ | |||
367 | /* 0x2e000000: system SRAM */ | |||
368 | memory_region_init_ram(sram, NULL((void*)0), "vexpress.a15sram", 0x10000); | |||
369 | vmstate_register_ram_global(sram); | |||
370 | memory_region_add_subregion(sysmem, 0x2e000000, sram); | |||
371 | ||||
372 | /* 0x7ffb0000: DMA330 DMA controller: not modelled */ | |||
373 | /* 0x7ffd0000: PL354 static memory controller: not modelled */ | |||
374 | } | |||
375 | ||||
376 | static const uint32_t a15_voltages[] = { | |||
377 | 900000, /* Vcore: 0.9V : CPU core voltage */ | |||
378 | }; | |||
379 | ||||
380 | static const uint32_t a15_clocks[] = { | |||
381 | 60000000, /* OSCCLK0: 60MHz : CPU_CLK reference */ | |||
382 | 0, /* OSCCLK1: reserved */ | |||
383 | 0, /* OSCCLK2: reserved */ | |||
384 | 0, /* OSCCLK3: reserved */ | |||
385 | 40000000, /* OSCCLK4: 40MHz : external AXI master clock */ | |||
386 | 23750000, /* OSCCLK5: 23.75MHz : HDLCD PLL reference */ | |||
387 | 50000000, /* OSCCLK6: 50MHz : static memory controller clock */ | |||
388 | 60000000, /* OSCCLK7: 60MHz : SYSCLK reference */ | |||
389 | 40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */ | |||
390 | }; | |||
391 | ||||
392 | static VEDBoardInfo a15_daughterboard = { | |||
393 | .motherboard_map = motherboard_aseries_map, | |||
394 | .loader_start = 0x80000000, | |||
395 | .gic_cpu_if_addr = 0x2c002000, | |||
396 | .proc_id = 0x14000237, | |||
397 | .num_voltage_sensors = ARRAY_SIZE(a15_voltages)(sizeof(a15_voltages) / sizeof((a15_voltages)[0])), | |||
398 | .voltages = a15_voltages, | |||
399 | .num_clocks = ARRAY_SIZE(a15_clocks)(sizeof(a15_clocks) / sizeof((a15_clocks)[0])), | |||
400 | .clocks = a15_clocks, | |||
401 | .init = a15_daughterboard_init, | |||
402 | }; | |||
403 | ||||
404 | static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, | |||
405 | hwaddr addr, hwaddr size, uint32_t intc, | |||
406 | int irq) | |||
407 | { | |||
408 | /* Add a virtio_mmio node to the device tree blob: | |||
409 | * virtio_mmio@ADDRESS { | |||
410 | * compatible = "virtio,mmio"; | |||
411 | * reg = <ADDRESS, SIZE>; | |||
412 | * interrupt-parent = <&intc>; | |||
413 | * interrupts = <0, irq, 1>; | |||
414 | * } | |||
415 | * (Note that the format of the interrupts property is dependent on the | |||
416 | * interrupt controller that interrupt-parent points to; these are for | |||
417 | * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.) | |||
418 | */ | |||
419 | int rc; | |||
420 | char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64"l" "x", addr); | |||
421 | ||||
422 | rc = qemu_fdt_add_subnode(fdt, nodename); | |||
423 | rc |= qemu_fdt_setprop_string(fdt, nodename, | |||
424 | "compatible", "virtio,mmio"); | |||
425 | rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",({ uint64_t qdt_tmp[] = { acells, addr, scells, size }; qemu_fdt_setprop_sized_cells_from_array (fdt, nodename, "reg", (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0] )) / 2, qdt_tmp); }) | |||
426 | acells, addr, scells, size)({ uint64_t qdt_tmp[] = { acells, addr, scells, size }; qemu_fdt_setprop_sized_cells_from_array (fdt, nodename, "reg", (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0] )) / 2, qdt_tmp); }); | |||
427 | qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc)do { uint32_t qdt_tmp[] = { intc }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp[i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, nodename, "interrupt-parent" , qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
428 | qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1)do { uint32_t qdt_tmp[] = { 0, irq, 1 }; int i; for (i = 0; i < (sizeof(qdt_tmp) / sizeof((qdt_tmp)[0])); i++) { qdt_tmp [i] = cpu_to_be32(qdt_tmp[i]); } qemu_fdt_setprop(fdt, nodename , "interrupts", qdt_tmp, sizeof(qdt_tmp)); } while (0); | |||
429 | g_free(nodename); | |||
430 | if (rc) { | |||
431 | return -1; | |||
432 | } | |||
433 | return 0; | |||
434 | } | |||
435 | ||||
436 | static uint32_t find_int_controller(void *fdt) | |||
437 | { | |||
438 | /* Find the FDT node corresponding to the interrupt controller | |||
439 | * for virtio-mmio devices. We do this by scanning the fdt for | |||
440 | * a node with the right compatibility, since we know there is | |||
441 | * only one GIC on a vexpress board. | |||
442 | * We return the phandle of the node, or 0 if none was found. | |||
443 | */ | |||
444 | const char *compat = "arm,cortex-a9-gic"; | |||
445 | int offset; | |||
446 | ||||
447 | offset = fdt_node_offset_by_compatible(fdt, -1, compat); | |||
448 | if (offset >= 0) { | |||
449 | return fdt_get_phandle(fdt, offset); | |||
450 | } | |||
451 | return 0; | |||
452 | } | |||
453 | ||||
454 | static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt) | |||
455 | { | |||
456 | uint32_t acells, scells, intc; | |||
457 | const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info; | |||
458 | ||||
459 | acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells"); | |||
460 | scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells"); | |||
461 | intc = find_int_controller(fdt); | |||
462 | if (!intc) { | |||
463 | /* Not fatal, we just won't provide virtio. This will | |||
464 | * happen with older device tree blobs. | |||
465 | */ | |||
466 | fprintf(stderrstderr, "QEMU: warning: couldn't find interrupt controller in " | |||
467 | "dtb; will not include virtio-mmio devices in the dtb.\n"); | |||
468 | } else { | |||
469 | int i; | |||
470 | const hwaddr *map = daughterboard->motherboard_map; | |||
471 | ||||
472 | /* We iterate backwards here because adding nodes | |||
473 | * to the dtb puts them in last-first. | |||
474 | */ | |||
475 | for (i = NUM_VIRTIO_TRANSPORTS4 - 1; i >= 0; i--) { | |||
476 | add_virtio_mmio_node(fdt, acells, scells, | |||
477 | map[VE_VIRTIO] + 0x200 * i, | |||
478 | 0x200, intc, 40 + i); | |||
479 | } | |||
480 | } | |||
481 | } | |||
482 | ||||
483 | ||||
484 | /* Open code a private version of pflash registration since we | |||
485 | * need to set non-default device width for VExpress platform. | |||
486 | */ | |||
487 | static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name, | |||
488 | DriveInfo *di) | |||
489 | { | |||
490 | DeviceState *dev = qdev_create(NULL((void*)0), "cfi.pflash01"); | |||
491 | ||||
492 | if (di && qdev_prop_set_drive(dev, "drive", di->bdrv)) { | |||
493 | abort(); | |||
494 | } | |||
495 | ||||
496 | qdev_prop_set_uint32(dev, "num-blocks", | |||
497 | VEXPRESS_FLASH_SIZE(64 * 1024 * 1024) / VEXPRESS_FLASH_SECT_SIZE(256 * 1024)); | |||
498 | qdev_prop_set_uint64(dev, "sector-length", VEXPRESS_FLASH_SECT_SIZE(256 * 1024)); | |||
499 | qdev_prop_set_uint8(dev, "width", 4); | |||
500 | qdev_prop_set_uint8(dev, "device-width", 2); | |||
501 | qdev_prop_set_uint8(dev, "big-endian", 0); | |||
502 | qdev_prop_set_uint16(dev, "id0", 0x89); | |||
503 | qdev_prop_set_uint16(dev, "id1", 0x18); | |||
504 | qdev_prop_set_uint16(dev, "id2", 0x00); | |||
505 | qdev_prop_set_uint16(dev, "id3", 0x00); | |||
506 | qdev_prop_set_string(dev, "name", name); | |||
507 | qdev_init_nofail(dev); | |||
508 | ||||
509 | sysbus_mmio_map(SYS_BUS_DEVICE(dev)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((dev) )), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 509, __func__)), 0, base); | |||
510 | return OBJECT_CHECK(pflash_t, (dev), "cfi.pflash01")((pflash_t *)object_dynamic_cast_assert(((Object *)((dev))), ( "cfi.pflash01"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 510, __func__)); | |||
511 | } | |||
512 | ||||
513 | static void vexpress_common_init(VEDBoardInfo *daughterboard, | |||
514 | QEMUMachineInitArgs *args) | |||
515 | { | |||
516 | DeviceState *dev, *sysctl, *pl041; | |||
517 | qemu_irq pic[64]; | |||
518 | uint32_t sys_id; | |||
519 | DriveInfo *dinfo; | |||
520 | pflash_t *pflash0; | |||
521 | ram_addr_t vram_size, sram_size; | |||
522 | MemoryRegion *sysmem = get_system_memory(); | |||
523 | MemoryRegion *vram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
524 | MemoryRegion *sram = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
525 | MemoryRegion *flashalias = g_new(MemoryRegion, 1)((MemoryRegion *) g_malloc_n ((1), sizeof (MemoryRegion))); | |||
526 | MemoryRegion *flash0mem; | |||
527 | const hwaddr *map = daughterboard->motherboard_map; | |||
528 | int i; | |||
529 | ||||
530 | daughterboard->init(daughterboard, args->ram_size, args->cpu_model, pic); | |||
531 | ||||
532 | /* Motherboard peripherals: the wiring is the same but the | |||
533 | * addresses vary between the legacy and A-Series memory maps. | |||
534 | */ | |||
535 | ||||
536 | sys_id = 0x1190f500; | |||
537 | ||||
538 | sysctl = qdev_create(NULL((void*)0), "realview_sysctl"); | |||
539 | qdev_prop_set_uint32(sysctl, "sys_id", sys_id); | |||
540 | qdev_prop_set_uint32(sysctl, "proc_id", daughterboard->proc_id); | |||
541 | qdev_prop_set_uint32(sysctl, "len-db-voltage", | |||
542 | daughterboard->num_voltage_sensors); | |||
543 | for (i = 0; i < daughterboard->num_voltage_sensors; i++) { | |||
544 | char *propname = g_strdup_printf("db-voltage[%d]", i); | |||
545 | qdev_prop_set_uint32(sysctl, propname, daughterboard->voltages[i]); | |||
546 | g_free(propname); | |||
547 | } | |||
548 | qdev_prop_set_uint32(sysctl, "len-db-clock", | |||
549 | daughterboard->num_clocks); | |||
550 | for (i = 0; i < daughterboard->num_clocks; i++) { | |||
551 | char *propname = g_strdup_printf("db-clock[%d]", i); | |||
552 | qdev_prop_set_uint32(sysctl, propname, daughterboard->clocks[i]); | |||
553 | g_free(propname); | |||
554 | } | |||
555 | qdev_init_nofail(sysctl); | |||
556 | sysbus_mmio_map(SYS_BUS_DEVICE(sysctl)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((sysctl ))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 556, __func__)), 0, map[VE_SYSREGS]); | |||
557 | ||||
558 | /* VE_SP810: not modelled */ | |||
559 | /* VE_SERIALPCI: not modelled */ | |||
560 | ||||
561 | pl041 = qdev_create(NULL((void*)0), "pl041"); | |||
562 | qdev_prop_set_uint32(pl041, "nc_fifo_depth", 512); | |||
563 | qdev_init_nofail(pl041); | |||
564 | sysbus_mmio_map(SYS_BUS_DEVICE(pl041)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((pl041 ))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 564, __func__)), 0, map[VE_PL041]); | |||
565 | sysbus_connect_irq(SYS_BUS_DEVICE(pl041)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((pl041 ))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 565, __func__)), 0, pic[11]); | |||
566 | ||||
567 | dev = sysbus_create_varargs("pl181", map[VE_MMCI], pic[9], pic[10], NULL((void*)0)); | |||
568 | /* Wire up MMC card detect and read-only signals */ | |||
569 | qdev_connect_gpio_out(dev, 0, | |||
570 | qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT0)); | |||
571 | qdev_connect_gpio_out(dev, 1, | |||
572 | qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN1)); | |||
573 | ||||
574 | sysbus_create_simple("pl050_keyboard", map[VE_KMI0], pic[12]); | |||
575 | sysbus_create_simple("pl050_mouse", map[VE_KMI1], pic[13]); | |||
576 | ||||
577 | sysbus_create_simple("pl011", map[VE_UART0], pic[5]); | |||
578 | sysbus_create_simple("pl011", map[VE_UART1], pic[6]); | |||
579 | sysbus_create_simple("pl011", map[VE_UART2], pic[7]); | |||
580 | sysbus_create_simple("pl011", map[VE_UART3], pic[8]); | |||
581 | ||||
582 | sysbus_create_simple("sp804", map[VE_TIMER01], pic[2]); | |||
583 | sysbus_create_simple("sp804", map[VE_TIMER23], pic[3]); | |||
584 | ||||
585 | /* VE_SERIALDVI: not modelled */ | |||
586 | ||||
587 | sysbus_create_simple("pl031", map[VE_RTC], pic[4]); /* RTC */ | |||
588 | ||||
589 | /* VE_COMPACTFLASH: not modelled */ | |||
590 | ||||
591 | sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); | |||
592 | ||||
593 | dinfo = drive_get_next(IF_PFLASH); | |||
594 | pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0", | |||
595 | dinfo); | |||
596 | if (!pflash0) { | |||
597 | fprintf(stderrstderr, "vexpress: error registering flash 0.\n"); | |||
598 | exit(1); | |||
599 | } | |||
600 | ||||
601 | if (map[VE_NORFLASHALIAS] != -1) { | |||
602 | /* Map flash 0 as an alias into low memory */ | |||
603 | flash0mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pflash0)((SysBusDevice *)object_dynamic_cast_assert(((Object *)((pflash0 ))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 603, __func__)), 0); | |||
604 | memory_region_init_alias(flashalias, NULL((void*)0), "vexpress.flashalias", | |||
605 | flash0mem, 0, VEXPRESS_FLASH_SIZE(64 * 1024 * 1024)); | |||
606 | memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias); | |||
607 | } | |||
608 | ||||
609 | dinfo = drive_get_next(IF_PFLASH); | |||
610 | if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1", | |||
611 | dinfo)) { | |||
612 | fprintf(stderrstderr, "vexpress: error registering flash 1.\n"); | |||
613 | exit(1); | |||
614 | } | |||
615 | ||||
616 | sram_size = 0x2000000; | |||
617 | memory_region_init_ram(sram, NULL((void*)0), "vexpress.sram", sram_size); | |||
618 | vmstate_register_ram_global(sram); | |||
619 | memory_region_add_subregion(sysmem, map[VE_SRAM], sram); | |||
620 | ||||
621 | vram_size = 0x800000; | |||
622 | memory_region_init_ram(vram, NULL((void*)0), "vexpress.vram", vram_size); | |||
623 | vmstate_register_ram_global(vram); | |||
624 | memory_region_add_subregion(sysmem, map[VE_VIDEORAM], vram); | |||
625 | ||||
626 | /* 0x4e000000 LAN9118 Ethernet */ | |||
627 | if (nd_table[0].used) { | |||
628 | lan9118_init(&nd_table[0], map[VE_ETHERNET], pic[15]); | |||
629 | } | |||
630 | ||||
631 | /* VE_USB: not modelled */ | |||
632 | ||||
633 | /* VE_DAPROM: not modelled */ | |||
634 | ||||
635 | /* Create mmio transports, so the user can create virtio backends | |||
636 | * (which will be automatically plugged in to the transports). If | |||
637 | * no backend is created the transport will just sit harmlessly idle. | |||
638 | */ | |||
639 | for (i = 0; i < NUM_VIRTIO_TRANSPORTS4; i++) { | |||
640 | sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i, | |||
641 | pic[40 + i]); | |||
642 | } | |||
643 | ||||
644 | daughterboard->bootinfo.ram_size = args->ram_size; | |||
645 | daughterboard->bootinfo.kernel_filename = args->kernel_filename; | |||
646 | daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline; | |||
647 | daughterboard->bootinfo.initrd_filename = args->initrd_filename; | |||
648 | daughterboard->bootinfo.nb_cpus = smp_cpus; | |||
649 | daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID0x8e0; | |||
650 | daughterboard->bootinfo.loader_start = daughterboard->loader_start; | |||
651 | daughterboard->bootinfo.smp_loader_start = map[VE_SRAM]; | |||
652 | daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30; | |||
653 | daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr; | |||
654 | daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb; | |||
655 | arm_load_kernel(ARM_CPU(first_cpu)((ARMCPU *)object_dynamic_cast_assert(((Object *)((((&cpus )->tqh_first)))), ("arm-cpu"), "/home/stefan/src/qemu/qemu.org/qemu/hw/arm/vexpress.c" , 655, __func__)), &daughterboard->bootinfo); | |||
656 | } | |||
657 | ||||
658 | static void vexpress_a9_init(QEMUMachineInitArgs *args) | |||
659 | { | |||
660 | vexpress_common_init(&a9_daughterboard, args); | |||
661 | } | |||
662 | ||||
663 | static void vexpress_a15_init(QEMUMachineInitArgs *args) | |||
664 | { | |||
665 | vexpress_common_init(&a15_daughterboard, args); | |||
666 | } | |||
667 | ||||
668 | static QEMUMachine vexpress_a9_machine = { | |||
669 | .name = "vexpress-a9", | |||
670 | .desc = "ARM Versatile Express for Cortex-A9", | |||
671 | .init = vexpress_a9_init, | |||
672 | .block_default_type = IF_SCSI, | |||
673 | .max_cpus = 4, | |||
674 | }; | |||
675 | ||||
676 | static QEMUMachine vexpress_a15_machine = { | |||
677 | .name = "vexpress-a15", | |||
678 | .desc = "ARM Versatile Express for Cortex-A15", | |||
679 | .init = vexpress_a15_init, | |||
680 | .block_default_type = IF_SCSI, | |||
681 | .max_cpus = 4, | |||
682 | }; | |||
683 | ||||
684 | static void vexpress_machine_init(void) | |||
685 | { | |||
686 | qemu_register_machine(&vexpress_a9_machine); | |||
687 | qemu_register_machine(&vexpress_a15_machine); | |||
688 | } | |||
689 | ||||
690 | machine_init(vexpress_machine_init)static void __attribute__((constructor)) do_qemu_init_vexpress_machine_init (void) { register_module_init(vexpress_machine_init, MODULE_INIT_MACHINE ); }; |