mirror of https://gitlab.com/qemu-project/qemu
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 "exec/address-spaces.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "hw/block/flash.h"
|
#include "hw/block/flash.h"
|
||||||
|
#include "sysemu/device_tree.h"
|
||||||
|
#include <libfdt.h>
|
||||||
|
|
||||||
#define VEXPRESS_BOARD_ID 0x8e0
|
#define VEXPRESS_BOARD_ID 0x8e0
|
||||||
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
|
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
|
||||||
#define VEXPRESS_FLASH_SECT_SIZE (256 * 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:
|
/* Address maps for peripherals:
|
||||||
* the Versatile Express motherboard has two possible maps,
|
* the Versatile Express motherboard has two possible maps,
|
||||||
* the "legacy" one (used for A9) and the "Cortex-A Series"
|
* the "legacy" one (used for A9) and the "Cortex-A Series"
|
||||||
|
@ -71,6 +78,7 @@ enum {
|
||||||
VE_ETHERNET,
|
VE_ETHERNET,
|
||||||
VE_USB,
|
VE_USB,
|
||||||
VE_DAPROM,
|
VE_DAPROM,
|
||||||
|
VE_VIRTIO,
|
||||||
};
|
};
|
||||||
|
|
||||||
static hwaddr motherboard_legacy_map[] = {
|
static hwaddr motherboard_legacy_map[] = {
|
||||||
|
@ -89,6 +97,7 @@ static hwaddr motherboard_legacy_map[] = {
|
||||||
[VE_WDT] = 0x1000f000,
|
[VE_WDT] = 0x1000f000,
|
||||||
[VE_TIMER01] = 0x10011000,
|
[VE_TIMER01] = 0x10011000,
|
||||||
[VE_TIMER23] = 0x10012000,
|
[VE_TIMER23] = 0x10012000,
|
||||||
|
[VE_VIRTIO] = 0x10013000,
|
||||||
[VE_SERIALDVI] = 0x10016000,
|
[VE_SERIALDVI] = 0x10016000,
|
||||||
[VE_RTC] = 0x10017000,
|
[VE_RTC] = 0x10017000,
|
||||||
[VE_COMPACTFLASH] = 0x1001a000,
|
[VE_COMPACTFLASH] = 0x1001a000,
|
||||||
|
@ -135,6 +144,7 @@ static hwaddr motherboard_aseries_map[] = {
|
||||||
[VE_WDT] = 0x1c0f0000,
|
[VE_WDT] = 0x1c0f0000,
|
||||||
[VE_TIMER01] = 0x1c110000,
|
[VE_TIMER01] = 0x1c110000,
|
||||||
[VE_TIMER23] = 0x1c120000,
|
[VE_TIMER23] = 0x1c120000,
|
||||||
|
[VE_VIRTIO] = 0x1c130000,
|
||||||
[VE_SERIALDVI] = 0x1c160000,
|
[VE_SERIALDVI] = 0x1c160000,
|
||||||
[VE_RTC] = 0x1c170000,
|
[VE_RTC] = 0x1c170000,
|
||||||
[VE_COMPACTFLASH] = 0x1c1a0000,
|
[VE_COMPACTFLASH] = 0x1c1a0000,
|
||||||
|
@ -395,6 +405,85 @@ static VEDBoardInfo a15_daughterboard = {
|
||||||
.init = a15_daughterboard_init,
|
.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,
|
static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||||
QEMUMachineInitArgs *args)
|
QEMUMachineInitArgs *args)
|
||||||
{
|
{
|
||||||
|
@ -523,6 +612,15 @@ static void vexpress_common_init(VEDBoardInfo *daughterboard,
|
||||||
|
|
||||||
/* VE_DAPROM: not modelled */
|
/* 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.ram_size = args->ram_size;
|
||||||
daughterboard->bootinfo.kernel_filename = args->kernel_filename;
|
daughterboard->bootinfo.kernel_filename = args->kernel_filename;
|
||||||
daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
|
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_loader_start = map[VE_SRAM];
|
||||||
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
|
||||||
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
|
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);
|
arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue