mirror of https://github.com/xemu-project/xemu.git
vexpress: Add virtio-mmio transports
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
This commit is contained in:
parent
cef04a26e7
commit
c8a07b355d
|
@ -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"
|
||||
|
@ -71,6 +78,7 @@ enum {
|
|||
VE_ETHERNET,
|
||||
VE_USB,
|
||||
VE_DAPROM,
|
||||
VE_VIRTIO,
|
||||
};
|
||||
|
||||
static hwaddr motherboard_legacy_map[] = {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue