Skip to content

Commit

Permalink
vexpress: Add virtio-mmio transports
Browse files Browse the repository at this point in the history
Add some virtio-mmio transports to the vexpress board model,
together with a modify_dtb hook which adds them to the device
tree so that the kernel will probe for them. We put them
in a reserved area of the address map.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1373977512-28932-9-git-send-email-peter.maydell@linaro.org
  • Loading branch information
pm215 committed Jul 19, 2013
1 parent cef04a2 commit c8a07b3
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions hw/arm/vexpress.c
Expand Up @@ -31,11 +31,18 @@
#include "exec/address-spaces.h"
#include "sysemu/blockdev.h"
#include "hw/block/flash.h"
#include "sysemu/device_tree.h"
#include <libfdt.h>

#define VEXPRESS_BOARD_ID 0x8e0
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)

/* Number of virtio transports to create (0..8; limited by
* number of available IRQ lines).
*/
#define NUM_VIRTIO_TRANSPORTS 4

/* Address maps for peripherals:
* the Versatile Express motherboard has two possible maps,
* the "legacy" one (used for A9) and the "Cortex-A Series"
Expand Down Expand Up @@ -71,6 +78,7 @@ enum {
VE_ETHERNET,
VE_USB,
VE_DAPROM,
VE_VIRTIO,
};

static hwaddr motherboard_legacy_map[] = {
Expand All @@ -89,6 +97,7 @@ static hwaddr motherboard_legacy_map[] = {
[VE_WDT] = 0x1000f000,
[VE_TIMER01] = 0x10011000,
[VE_TIMER23] = 0x10012000,
[VE_VIRTIO] = 0x10013000,
[VE_SERIALDVI] = 0x10016000,
[VE_RTC] = 0x10017000,
[VE_COMPACTFLASH] = 0x1001a000,
Expand Down Expand Up @@ -135,6 +144,7 @@ static hwaddr motherboard_aseries_map[] = {
[VE_WDT] = 0x1c0f0000,
[VE_TIMER01] = 0x1c110000,
[VE_TIMER23] = 0x1c120000,
[VE_VIRTIO] = 0x1c130000,
[VE_SERIALDVI] = 0x1c160000,
[VE_RTC] = 0x1c170000,
[VE_COMPACTFLASH] = 0x1c1a0000,
Expand Down Expand Up @@ -395,6 +405,85 @@ static VEDBoardInfo a15_daughterboard = {
.init = a15_daughterboard_init,
};

static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
hwaddr addr, hwaddr size, uint32_t intc,
int irq)
{
/* Add a virtio_mmio node to the device tree blob:
* virtio_mmio@ADDRESS {
* compatible = "virtio,mmio";
* reg = <ADDRESS, SIZE>;
* interrupt-parent = <&intc>;
* interrupts = <0, irq, 1>;
* }
* (Note that the format of the interrupts property is dependent on the
* interrupt controller that interrupt-parent points to; these are for
* the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
*/
int rc;
char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr);

rc = qemu_devtree_add_subnode(fdt, nodename);
rc |= qemu_devtree_setprop_string(fdt, nodename,
"compatible", "virtio,mmio");
rc |= qemu_devtree_setprop_sized_cells(fdt, nodename, "reg",
acells, addr, scells, size);
qemu_devtree_setprop_cells(fdt, nodename, "interrupt-parent", intc);
qemu_devtree_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
g_free(nodename);
if (rc) {
return -1;
}
return 0;
}

static uint32_t find_int_controller(void *fdt)
{
/* Find the FDT node corresponding to the interrupt controller
* for virtio-mmio devices. We do this by scanning the fdt for
* a node with the right compatibility, since we know there is
* only one GIC on a vexpress board.
* We return the phandle of the node, or 0 if none was found.
*/
const char *compat = "arm,cortex-a9-gic";
int offset;

offset = fdt_node_offset_by_compatible(fdt, -1, compat);
if (offset >= 0) {
return fdt_get_phandle(fdt, offset);
}
return 0;
}

static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
uint32_t acells, scells, intc;
const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;

acells = qemu_devtree_getprop_cell(fdt, "/", "#address-cells");
scells = qemu_devtree_getprop_cell(fdt, "/", "#size-cells");
intc = find_int_controller(fdt);
if (!intc) {
/* Not fatal, we just won't provide virtio. This will
* happen with older device tree blobs.
*/
fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
"dtb; will not include virtio-mmio devices in the dtb.\n");
} else {
int i;
const hwaddr *map = daughterboard->motherboard_map;

/* We iterate backwards here because adding nodes
* to the dtb puts them in last-first.
*/
for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
add_virtio_mmio_node(fdt, acells, scells,
map[VE_VIRTIO] + 0x200 * i,
0x200, intc, 40 + i);
}
}
}

static void vexpress_common_init(VEDBoardInfo *daughterboard,
QEMUMachineInitArgs *args)
{
Expand Down Expand Up @@ -523,6 +612,15 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,

/* VE_DAPROM: not modelled */

/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
*/
for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i,
pic[40 + i]);
}

daughterboard->bootinfo.ram_size = args->ram_size;
daughterboard->bootinfo.kernel_filename = args->kernel_filename;
daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
Expand All @@ -533,6 +631,7 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}

Expand Down

0 comments on commit c8a07b3

Please sign in to comment.