/*
* ARM Versatile Express emulation.
*
* Copyright (c) 2010 - 2011 B Labs Ltd.
* Copyright (c) 2011 Linaro Limited
* Written by Bahadir Balban, Amit Mahajan, Peter Maydell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see .
*
* Contributions after 2012-01-13 are licensed under the terms of the
* GNU GPL, version 2 or (at your option) any later version.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/datadir.h"
#include "cpu.h"
#include "hw/sysbus.h"
#include "hw/arm/boot.h"
#include "hw/arm/primecell.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
#include "hw/boards.h"
#include "hw/loader.h"
#include "sysemu/device_tree.h"
#include "qemu/error-report.h"
#include
#include "hw/char/bcm2835_aux.h"
// #include "hw/cpu/a9mpcore.h"
#include "hw/sd/sd.h"
#include "qom/object.h"
#include "kvm_arm.h"
/* 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"
* map (used for newer cores).
* Individual daughterboards can also have different maps for
* their peripherals.
*/
enum {
VE_NORFLASH0,
VE_SYSREGS,
VE_UART0,
VE_UART1,
VE_TIMER01,
VE_SRAM,
VE_VIRTIO
};
static hwaddr motherboard_aseries_map[] = {
[VE_NORFLASH0] = 0x00000000,
[VE_SYSREGS] = 0x01000000,
[VE_UART0] = 0x021C0000,
[VE_UART1] = 0x021D0000,
[VE_TIMER01] = 0x01EE1000,
[VE_SRAM] = 0x80000000,
};
typedef struct LSDBoardInfo LSDBoardInfo;
struct LayerscpMachineClass {
MachineClass parent;
LSDBoardInfo *daughterboard;
};
struct LayerscpMachineState {
MachineState parent;
bool secure;
bool virt;
uint32_t gic_version;
};
#define TYPE_LS1046A_MACHINE "ls1046a"
#define TYPE_LS1046A_1_MACHINE MACHINE_TYPE_NAME("ls1046a-1")
//#define LS1046A_MACHINE_CLASS(klass) OBJECT_CLASS_CHECK(LayerscpMachineClass, klass, TYPE_LS1046A_MACHINE)
OBJECT_DECLARE_TYPE(LayerscpMachineState, LayerscpMachineClass, LS1046A_MACHINE)
typedef void DBoardInitFn(const LayerscpMachineState *machine,
ram_addr_t ram_size,
const char *cpu_type,
qemu_irq *gic);
struct LSDBoardInfo {
struct arm_boot_info bootinfo;
const hwaddr *motherboard_map;
hwaddr loader_start;
const hwaddr gic_cpu_if_addr;
uint32_t proc_id;
uint32_t num_voltage_sensors;
const uint32_t *voltages;
uint32_t num_clocks;
const uint32_t *clocks;
DBoardInitFn *init;
};
static void init_cpus(MachineState *ms, const char *cpu_type,
const char *privdev, hwaddr periphbase,
qemu_irq *gic, bool secure, bool virt)
{
DeviceState *dev;
SysBusDevice *busdev;
int n;
unsigned int smp_cpus = ms->smp.cpus;
const char *gictype;
//gictype = gicv3_class_name();
/* Create the actual CPUs */
printf("smp_cpus: %u\n", smp_cpus);
printf("cpu_type: %s\n", cpu_type);
for (n = 0; n < smp_cpus; n++) {
Object *cpuobj = object_new(cpu_type);
if (!secure) {
object_property_set_bool(cpuobj, "has_el3", false, NULL);
}
if (!virt) {
if (object_property_find(cpuobj, "has_el2")) {
object_property_set_bool(cpuobj, "has_el2", false, NULL);
}
}
if (object_property_find(cpuobj, "reset-cbar")) {
object_property_set_int(cpuobj, "reset-cbar", periphbase,
&error_abort);
}
qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
}
/* Create the private peripheral devices (including the GIC);
* this must happen after the CPUs are created because a15mpcore_priv
* wires itself up to the CPU's generic_timer gpio out lines.
*/
dev = qdev_new(privdev);
//dev = qdev_new(gictype);;
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
busdev = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(busdev, &error_fatal);
sysbus_mmio_map(busdev, 0, periphbase);
///* Connect the CPUs to the GIC */
//for (n = 0; n < smp_cpus; n++) {
// DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
//
// sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
// sysbus_connect_irq(busdev, n + smp_cpus,
// qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
// sysbus_connect_irq(busdev, n + 2 * smp_cpus,
// qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
// sysbus_connect_irq(busdev, n + 3 * smp_cpus,
// qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
//}
}
static void a72_daughterboard_init(const LayerscpMachineState *vms,
ram_addr_t ram_size,
const char *cpu_type,
qemu_irq *gic)
{
MachineState *machine = MACHINE(vms);
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *lowram = g_new(MemoryRegion, 1);
ram_addr_t low_ram_size;
if (ram_size > 0x80000000U) {
/* 2GB is the maximum the address space permits */
error_report("ls1046a-a72: cannot model more than 2GB RAM");
exit(1);
}
low_ram_size = ram_size;
if (low_ram_size > 0x80000000U) {
low_ram_size = 0x80000000U;
}
/* RAM is from 0x60000000 upwards. The bottom 64MB of the
* address space should in theory be remappable to various
* things including ROM or RAM; we always map the RAM there.
*/
memory_region_init_alias(lowram, NULL, "ls1046a.lowmem", machine->ram,
0, low_ram_size);
memory_region_add_subregion(sysmem, 0x0, lowram);
memory_region_add_subregion(sysmem, 0x80000000, machine->ram);
/* 0x1400000 private memory region */
init_cpus(machine, cpu_type, "a9mpcore_priv", 0x1400000, gic,
vms->secure, vms->virt);
/* Daughterboard peripherals : 0x10020000 .. 0x20000000 */
/* 0x10020000 PL111 CLCD (daughterboard) */
// sysbus_create_simple("pl111", 0x10020000, gic[44]);
/* 0x10060000 AXI RAM */
/* 0x100e0000 PL341 Dynamic Memory Controller */
/* 0x100e1000 PL354 Static Memory Controller */
/* 0x100e2000 System Configuration Controller */
// sysbus_create_simple("sp804", 0x100e4000, gic[48]);
/* 0x100e5000 SP805 Watchdog module */
/* 0x100e6000 BP147 TrustZone Protection Controller */
/* 0x100e9000 PL301 'Fast' AXI matrix */
/* 0x100ea000 PL301 'Slow' AXI matrix */
/* 0x100ec000 TrustZone Address Space Controller */
/* 0x10200000 CoreSight debug APB */
/* 0x1e00a000 PL310 L2 Cache Controller */
// sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
}
/* Voltage values for SYS_CFG_VOLT daughterboard registers;
* values are in microvolts.
*/
static const uint32_t a72_voltages[] = {
1000000, /* VD10 : 1.0V : SoC internal logic voltage */
1000000, /* VD10_S2 : 1.0V : PL310, L2 cache, RAM, non-PL310 logic */
1000000, /* VD10_S3 : 1.0V : Cortex-A9, cores, MPEs, SCU, PL310 logic */
1800000, /* VCC1V8 : 1.8V : DDR2 SDRAM, test chip DDR2 I/O supply */
900000, /* DDR2VTT : 0.9V : DDR2 SDRAM VTT termination voltage */
3300000, /* VCC3V3 : 3.3V : local board supply for misc external logic */
};
/* Reset values for daughterboard oscillators (in Hz) */
static const uint32_t a72_clocks[] = {
45000000, /* AMBA AXI ACLK: 45MHz */
23750000, /* daughterboard CLCD clock: 23.75MHz */
66670000, /* Test chip reference clock: 66.67MHz */
};
static LSDBoardInfo a72_daughterboard = {
.motherboard_map = motherboard_aseries_map,
.loader_start = 0x80004000,
.gic_cpu_if_addr = 0x01420000,
.proc_id = 0x0c000191,
.num_voltage_sensors = ARRAY_SIZE(a72_voltages),
.voltages = a72_voltages,
.num_clocks = ARRAY_SIZE(a72_clocks),
.clocks = a72_clocks,
.init = a72_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 = ;
* 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_fdt_add_subnode(fdt, nodename);
rc |= qemu_fdt_setprop_string(fdt, nodename,
"compatible", "virtio,mmio");
rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, addr, scells, size);
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc);
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
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 ls1046a board.
* We return the phandle of the node, or 0 if none was found.
*/
const char *compat = "arm,cortex-a72-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 ls1046a_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
uint32_t acells, scells, intc;
const LSDBoardInfo *daughterboard = (const LSDBoardInfo *)info;
acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells",
NULL, &error_fatal);
scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells",
NULL, &error_fatal);
intc = find_int_controller(fdt);
if (!intc) {
/* Not fatal, we just won't provide virtio. This will
* happen with older device tree blobs.
*/
warn_report("couldn't find interrupt controller in "
"dtb; will not include virtio-mmio devices in the dtb");
} 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 ls1046a_common_init(MachineState *machine)
{
LayerscpMachineState *vms = LS1046A_MACHINE(machine);
LayerscpMachineClass *vmc = LS1046A_MACHINE_GET_CLASS(machine);
LSDBoardInfo *daughterboard = vmc->daughterboard;
DeviceState *dev, *sysctl, *serdev;
qemu_irq pic[64];
qemu_irq gic[64];
ram_addr_t sram_size;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *sram = g_new(MemoryRegion, 1);
const hwaddr *map = daughterboard->motherboard_map;
int i;
daughterboard->init(vms, machine->ram_size, machine->cpu_type, pic);
/*
* If a bios file was provided, attempt to map it into memory
*/
if (machine->firmware) {
char *fn;
int image_size;
if (drive_get(IF_PFLASH, 0, 0)) {
error_report("The contents of the first flash device may be "
"specified with -bios or with -drive if=pflash... "
"but you cannot use both options at once");
exit(1);
}
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware);
if (!fn) {
error_report("Could not find ROM image '%s'", machine->firmware);
exit(1);
}
// image_size = load_image_targphys(fn, map[VE_NORFLASH0],
// LS1046A_FLASH_SIZE);
// g_free(fn);
// if (image_size < 0) {
// error_report("Could not load ROM image '%s'", machine->firmware);
// exit(1);
// }
}
sysbus_realize_and_unref(SYS_BUS_DEVICE(sysctl), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, map[VE_SYSREGS]);
serdev = qdev_new("duart1");
// pl011_create(, gic[5], serial_hd(0));
sysbus_mmio_map(SYS_BUS_DEVICE(serdev), 0, map[VE_UART0]);
// sysbus_mmio_map(SYS_BUS_DEVICE(serdev), 0, map[VE_UART1]);
// pl011_create(map[VE_UART1], gic[6], serial_hd(1));
sysbus_create_simple("sp804", map[VE_TIMER01], gic[2]);
sram_size = 0x80000000;
memory_region_init_ram(sram, NULL, "ls1046a.sram", sram_size,
&error_fatal);
memory_region_add_subregion(sysmem, map[VE_SRAM], sram);
/* VE_USB: 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,
// gic[40 + i]);
// }
daughterboard->bootinfo.ram_size = machine->ram_size;
daughterboard->bootinfo.board_id = 0x12345678;
daughterboard->bootinfo.loader_start = daughterboard->loader_start;
daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
daughterboard->bootinfo.smp_bootreg_addr = map[VE_SRAM] + 0x4000;
daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
daughterboard->bootinfo.modify_dtb = ls1046a_modify_dtb;
/* When booting Linux we should be in secure state if the CPU has one. */
daughterboard->bootinfo.secure_boot = vms->secure;
arm_load_kernel(ARM_CPU(first_cpu), machine, &daughterboard->bootinfo);
}
static bool ls1046a_get_secure(Object *obj, Error **errp)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
return vms->secure;
}
static void ls1046a_set_secure(Object *obj, bool value, Error **errp)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
vms->secure = value;
}
static void ls1046a_set_gic_version(Object *obj, const char *value, Error **errp)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
if (!strcmp(value, "4")) {
vms->gic_version = 4;
} else if (!strcmp(value, "3")) {
vms->gic_version = 3;
} else if (!strcmp(value, "2")) {
vms->gic_version = 2;
} else if (!strcmp(value, "host")) {
vms->gic_version = 1; /* Will probe later */
} else if (!strcmp(value, "max")) {
vms->gic_version = 0; /* Will probe later */
} else {
error_setg(errp, "Invalid gic-version value");
error_append_hint(errp, "Valid values are 3, 2, host, max.\n");
}
}
static bool ls1046a_get_virt(Object *obj, Error **errp)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
return vms->virt;
}
static void ls1046a_set_virt(Object *obj, bool value, Error **errp)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
vms->virt = value;
}
static void layerscape_instance_init(Object *obj)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
/* EL3 is enabled by default on ls1046a */
vms->secure = true;
vms->virt = true;
//vms->gic = 3;
}
static void ls1046a_instance_init(Object *obj)
{
LayerscpMachineState *vms = LS1046A_MACHINE(obj);
/* EL3 is enabled by default on ls1046a */
vms->secure = true;
vms->virt = true;
//vms->gic = 3;
}
static void layerscape_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "ARM Real Time Experiment (RTX)";
mc->init = ls1046a_common_init;
mc->max_cpus = 4; // single core
mc->ignore_memory_transaction_failures = true;
mc->default_ram_id = "ls1046a.highmem";
}
static void ls1046a_class_init(ObjectClass *oc, void *data)
{
const char gic_ver[2] = "2";
MachineClass *mc = MACHINE_CLASS(oc);
LayerscpMachineClass *vmc = LS1046A_MACHINE_CLASS(oc);
mc->desc = "Layerscape 1046ARDB";
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a72");
vmc->daughterboard = &a72_daughterboard;
}
static const TypeInfo layerscape_info = {
.name = TYPE_LS1046A_MACHINE,
.parent = TYPE_MACHINE,
.abstract = true,
.instance_size = sizeof(LayerscpMachineState),
.instance_init = layerscape_instance_init,
.class_size = sizeof(LayerscpMachineClass),
.class_init = layerscape_class_init,
};
static const TypeInfo ls1046a_info = {
.name = TYPE_LS1046A_1_MACHINE,
.parent = TYPE_LS1046A_MACHINE,
//.parent = TYPE_MACHINE,
.instance_init = ls1046a_instance_init,
.class_init = ls1046a_class_init,
};
static void ls1046a_machine_init(void)
{
type_register_static(&layerscape_info);
type_register_static(&ls1046a_info);
}
type_init(ls1046a_machine_init);