| File: | hw/arm/vexpress.c |
| Location: | line 230, 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 ); }; |