aboutsummaryrefslogtreecommitdiff
path: root/hw/arm
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm')
-rw-r--r--hw/arm/Kconfig1
-rw-r--r--hw/arm/armsse.c20
-rw-r--r--hw/arm/armv7m.c260
-rw-r--r--hw/arm/mps2.c17
-rw-r--r--hw/arm/msf2-soc.c68
-rw-r--r--hw/arm/msf2-som.c7
-rw-r--r--hw/arm/netduino2.c12
-rw-r--r--hw/arm/netduinoplus2.c12
-rw-r--r--hw/arm/nrf51_soc.c20
-rw-r--r--hw/arm/raspi.c2
-rw-r--r--hw/arm/stellaris.c396
-rw-r--r--hw/arm/stm32f100_soc.c47
-rw-r--r--hw/arm/stm32f205_soc.c47
-rw-r--r--hw/arm/stm32f405_soc.c30
-rw-r--r--hw/arm/stm32vldiscovery.c13
-rw-r--r--hw/arm/virt.c10
16 files changed, 523 insertions, 439 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index dc050b5c37..78fdd1b935 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -235,6 +235,7 @@ config STELLARIS
select SSI_SD
select STELLARIS_INPUT
select STELLARIS_ENET # ethernet
+ select STELLARIS_GPTM # general purpose timer module
select UNIMP
config STM32VLDISCOVERY
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c
index a1456cb0f4..aecdeb9815 100644
--- a/hw/arm/armsse.c
+++ b/hw/arm/armsse.c
@@ -689,17 +689,6 @@ static void armsse_forward_sec_resp_cfg(ARMSSE *s)
qdev_connect_gpio_out(dev_splitter, 2, s->sec_resp_cfg_in);
}
-static void armsse_mainclk_update(void *opaque, ClockEvent event)
-{
- ARMSSE *s = ARM_SSE(opaque);
-
- /*
- * Set system_clock_scale from our Clock input; this is what
- * controls the tick rate of the CPU SysTick timer.
- */
- system_clock_scale = clock_ticks_to_ns(s->mainclk, 1);
-}
-
static void armsse_init(Object *obj)
{
ARMSSE *s = ARM_SSE(obj);
@@ -711,8 +700,7 @@ static void armsse_init(Object *obj)
assert(info->sram_banks <= MAX_SRAM_BANKS);
assert(info->num_cpus <= SSE_MAX_CPUS);
- s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK",
- armsse_mainclk_update, s, ClockUpdate);
+ s->mainclk = qdev_init_clock_in(DEVICE(s), "MAINCLK", NULL, NULL, 0);
s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL, 0);
memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
@@ -995,6 +983,9 @@ static void armsse_realize(DeviceState *dev, Error **errp)
int j;
char *gpioname;
+ qdev_connect_clock_in(cpudev, "cpuclk", s->mainclk);
+ /* The SSE subsystems do not wire up a systick refclk */
+
qdev_prop_set_uint32(cpudev, "num-irq", s->exp_numirq + NUM_SSE_IRQS);
/*
* In real hardware the initial Secure VTOR is set from the INITSVTOR*
@@ -1651,9 +1642,6 @@ static void armsse_realize(DeviceState *dev, Error **errp)
* devices in the ARMSSE.
*/
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
-
- /* Set initial system_clock_scale from MAINCLK */
- armsse_mainclk_update(s, ClockUpdate);
}
static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c
index 9ce5c30cd5..8d08db80be 100644
--- a/hw/arm/armv7m.c
+++ b/hw/arm/armv7m.c
@@ -14,11 +14,14 @@
#include "hw/arm/boot.h"
#include "hw/loader.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "elf.h"
#include "sysemu/reset.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "qemu/log.h"
#include "target/arm/idau.h"
+#include "migration/vmstate.h"
/* Bitbanded IO. Each word corresponds to a single bit. */
@@ -124,6 +127,122 @@ static const hwaddr bitband_output_addr[ARMV7M_NUM_BITBANDS] = {
0x22000000, 0x42000000
};
+static MemTxResult v7m_sysreg_ns_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ MemoryRegion *mr = opaque;
+
+ if (attrs.secure) {
+ /* S accesses to the alias act like NS accesses to the real region */
+ attrs.secure = 0;
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
+ } else {
+ /* NS attrs are RAZ/WI for privileged, and BusFault for user */
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ return MEMTX_OK;
+ }
+}
+
+static MemTxResult v7m_sysreg_ns_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ MemoryRegion *mr = opaque;
+
+ if (attrs.secure) {
+ /* S accesses to the alias act like NS accesses to the real region */
+ attrs.secure = 0;
+ return memory_region_dispatch_read(mr, addr, data,
+ size_memop(size) | MO_TE, attrs);
+ } else {
+ /* NS attrs are RAZ/WI for privileged, and BusFault for user */
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ *data = 0;
+ return MEMTX_OK;
+ }
+}
+
+static const MemoryRegionOps v7m_sysreg_ns_ops = {
+ .read_with_attrs = v7m_sysreg_ns_read,
+ .write_with_attrs = v7m_sysreg_ns_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static MemTxResult v7m_systick_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ ARMv7MState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_write(mr, addr, value,
+ size_memop(size) | MO_TE, attrs);
+}
+
+static MemTxResult v7m_systick_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ ARMv7MState *s = opaque;
+ MemoryRegion *mr;
+
+ /* Direct the access to the correct systick */
+ mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->systick[attrs.secure]), 0);
+ return memory_region_dispatch_read(mr, addr, data, size_memop(size) | MO_TE,
+ attrs);
+}
+
+static const MemoryRegionOps v7m_systick_ops = {
+ .read_with_attrs = v7m_systick_read,
+ .write_with_attrs = v7m_systick_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+/*
+ * Unassigned portions of the PPB space are RAZ/WI for privileged
+ * accesses, and fault for non-privileged accesses.
+ */
+static MemTxResult ppb_default_read(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ qemu_log_mask(LOG_UNIMP, "Read of unassigned area of PPB: offset 0x%x\n",
+ (uint32_t)addr);
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ *data = 0;
+ return MEMTX_OK;
+}
+
+static MemTxResult ppb_default_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size,
+ MemTxAttrs attrs)
+{
+ qemu_log_mask(LOG_UNIMP, "Write of unassigned area of PPB: offset 0x%x\n",
+ (uint32_t)addr);
+ if (attrs.user) {
+ return MEMTX_ERROR;
+ }
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps ppb_default_ops = {
+ .read_with_attrs = ppb_default_read,
+ .write_with_attrs = ppb_default_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+};
+
static void armv7m_instance_init(Object *obj)
{
ARMv7MState *s = ARMV7M(obj);
@@ -137,10 +256,20 @@ static void armv7m_instance_init(Object *obj)
object_property_add_alias(obj, "num-irq",
OBJECT(&s->nvic), "num-irq");
+ object_initialize_child(obj, "systick-reg-ns", &s->systick[M_REG_NS],
+ TYPE_SYSTICK);
+ /*
+ * We can't initialize the secure systick here, as we don't know
+ * yet if we need it.
+ */
+
for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
object_initialize_child(obj, "bitband[*]", &s->bitband[i],
TYPE_BITBAND);
}
+
+ s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", NULL, NULL, 0);
+ s->cpuclk = qdev_init_clock_in(DEVICE(obj), "cpuclk", NULL, NULL, 0);
}
static void armv7m_realize(DeviceState *dev, Error **errp)
@@ -223,13 +352,130 @@ static void armv7m_realize(DeviceState *dev, Error **errp)
qdev_pass_gpios(DEVICE(&s->nvic), dev, "SYSRESETREQ");
qdev_pass_gpios(DEVICE(&s->nvic), dev, "NMI");
+ /*
+ * We map various devices into the container MR at their architected
+ * addresses. In particular, we map everything corresponding to the
+ * "System PPB" space. This is the range from 0xe0000000 to 0xe00fffff
+ * and includes the NVIC, the System Control Space (system registers),
+ * the systick timer, and for CPUs with the Security extension an NS
+ * banked version of all of these.
+ *
+ * The default behaviour for unimplemented registers/ranges
+ * (for instance the Data Watchpoint and Trace unit at 0xe0001000)
+ * is to RAZ/WI for privileged access and BusFault for non-privileged
+ * access.
+ *
+ * The NVIC and System Control Space (SCS) starts at 0xe000e000
+ * and looks like this:
+ * 0x004 - ICTR
+ * 0x010 - 0xff - systick
+ * 0x100..0x7ec - NVIC
+ * 0x7f0..0xcff - Reserved
+ * 0xd00..0xd3c - SCS registers
+ * 0xd40..0xeff - Reserved or Not implemented
+ * 0xf00 - STIR
+ *
+ * Some registers within this space are banked between security states.
+ * In v8M there is a second range 0xe002e000..0xe002efff which is the
+ * NonSecure alias SCS; secure accesses to this behave like NS accesses
+ * to the main SCS range, and non-secure accesses (including when
+ * the security extension is not implemented) are RAZ/WI.
+ * Note that both the main SCS range and the alias range are defined
+ * to be exempt from memory attribution (R_BLJT) and so the memory
+ * transaction attribute always matches the current CPU security
+ * state (attrs.secure == env->v7m.secure). In the v7m_sysreg_ns_ops
+ * wrappers we change attrs.secure to indicate the NS access; so
+ * generally code determining which banked register to use should
+ * use attrs.secure; code determining actual behaviour of the system
+ * should use env->v7m.secure.
+ *
+ * Within the PPB space, some MRs overlap, and the priority
+ * of overlapping regions is:
+ * - default region (for RAZ/WI and BusFault) : -1
+ * - system register regions (provided by the NVIC) : 0
+ * - systick : 1
+ * This is because the systick device is a small block of registers
+ * in the middle of the other system control registers.
+ */
+
+ memory_region_init_io(&s->defaultmem, OBJECT(s), &ppb_default_ops, s,
+ "nvic-default", 0x100000);
+ memory_region_add_subregion_overlap(&s->container, 0xe0000000,
+ &s->defaultmem, -1);
+
/* Wire the NVIC up to the CPU */
sbd = SYS_BUS_DEVICE(&s->nvic);
sysbus_connect_irq(sbd, 0,
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ));
- memory_region_add_subregion(&s->container, 0xe0000000,
+ memory_region_add_subregion(&s->container, 0xe000e000,
sysbus_mmio_get_region(sbd, 0));
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
+ /* Create the NS alias region for the NVIC sysregs */
+ memory_region_init_io(&s->sysreg_ns_mem, OBJECT(s),
+ &v7m_sysreg_ns_ops,
+ sysbus_mmio_get_region(sbd, 0),
+ "nvic_sysregs_ns", 0x1000);
+ memory_region_add_subregion(&s->container, 0xe002e000,
+ &s->sysreg_ns_mem);
+ }
+
+ /* Create and map the systick devices */
+ qdev_connect_clock_in(DEVICE(&s->systick[M_REG_NS]), "refclk", s->refclk);
+ qdev_connect_clock_in(DEVICE(&s->systick[M_REG_NS]), "cpuclk", s->cpuclk);
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), errp)) {
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_NS]), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->nvic),
+ "systick-trigger", M_REG_NS));
+
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_M_SECURITY)) {
+ /*
+ * We couldn't init the secure systick device in instance_init
+ * as we didn't know then if the CPU had the security extensions;
+ * so we have to do it here.
+ */
+ object_initialize_child(OBJECT(dev), "systick-reg-s",
+ &s->systick[M_REG_S], TYPE_SYSTICK);
+ qdev_connect_clock_in(DEVICE(&s->systick[M_REG_S]), "refclk",
+ s->refclk);
+ qdev_connect_clock_in(DEVICE(&s->systick[M_REG_S]), "cpuclk",
+ s->cpuclk);
+
+ if (!sysbus_realize(SYS_BUS_DEVICE(&s->systick[M_REG_S]), errp)) {
+ return;
+ }
+ sysbus_connect_irq(SYS_BUS_DEVICE(&s->systick[M_REG_S]), 0,
+ qdev_get_gpio_in_named(DEVICE(&s->nvic),
+ "systick-trigger", M_REG_S));
+ }
+
+ memory_region_init_io(&s->systickmem, OBJECT(s),
+ &v7m_systick_ops, s,
+ "v7m_systick", 0xe0);
+
+ memory_region_add_subregion_overlap(&s->container, 0xe000e010,
+ &s->systickmem, 1);
+ if (arm_feature(&s->cpu->env, ARM_FEATURE_V8)) {
+ memory_region_init_io(&s->systick_ns_mem, OBJECT(s),
+ &v7m_sysreg_ns_ops, &s->systickmem,
+ "v7m_systick_ns", 0xe0);
+ memory_region_add_subregion_overlap(&s->container, 0xe002e010,
+ &s->systick_ns_mem, 1);
+ }
+
+ /* If the CPU has RAS support, create the RAS register block */
+ if (cpu_isar_feature(aa32_ras, s->cpu)) {
+ object_initialize_child(OBJECT(dev), "armv7m-ras",
+ &s->ras, TYPE_ARMV7M_RAS);
+ sbd = SYS_BUS_DEVICE(&s->ras);
+ if (!sysbus_realize(sbd, errp)) {
+ return;
+ }
+ memory_region_add_subregion_overlap(&s->container, 0xe0005000,
+ sysbus_mmio_get_region(sbd, 0), 1);
+ }
for (i = 0; i < ARRAY_SIZE(s->bitband); i++) {
if (s->enable_bitband) {
@@ -269,11 +515,23 @@ static Property armv7m_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static const VMStateDescription vmstate_armv7m = {
+ .name = "armv7m",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_CLOCK(refclk, SysTickState),
+ VMSTATE_CLOCK(cpuclk, SysTickState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void armv7m_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = armv7m_realize;
+ dc->vmsd = &vmstate_armv7m;
device_class_set_props(dc, armv7m_properties);
}
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
index 81413b7133..4634aa1a1c 100644
--- a/hw/arm/mps2.c
+++ b/hw/arm/mps2.c
@@ -86,6 +86,7 @@ struct MPS2MachineState {
CMSDKAPBWatchdog watchdog;
CMSDKAPBTimer timer[2];
Clock *sysclk;
+ Clock *refclk;
};
#define TYPE_MPS2_MACHINE "mps2"
@@ -99,6 +100,15 @@ OBJECT_DECLARE_TYPE(MPS2MachineState, MPS2MachineClass, MPS2_MACHINE)
/* Main SYSCLK frequency in Hz */
#define SYSCLK_FRQ 25000000
+/*
+ * The Application Notes don't say anything about how the
+ * systick reference clock is configured. (Quite possibly
+ * they don't have one at all.) This 1MHz clock matches the
+ * pre-existing behaviour that used to be hardcoded in the
+ * armv7m_systick implementation.
+ */
+#define REFCLK_FRQ (1 * 1000 * 1000)
+
/* Initialize the auxiliary RAM region @mr and map it into
* the memory map at @base.
*/
@@ -146,6 +156,9 @@ static void mps2_common_init(MachineState *machine)
mms->sysclk = clock_new(OBJECT(machine), "SYSCLK");
clock_set_hz(mms->sysclk, SYSCLK_FRQ);
+ mms->refclk = clock_new(OBJECT(machine), "REFCLK");
+ clock_set_hz(mms->refclk, REFCLK_FRQ);
+
/* The FPGA images have an odd combination of different RAMs,
* because in hardware they are different implementations and
* connected to different buses, giving varying performance/size
@@ -223,6 +236,8 @@ static void mps2_common_init(MachineState *machine)
default:
g_assert_not_reached();
}
+ qdev_connect_clock_in(armv7m, "cpuclk", mms->sysclk);
+ qdev_connect_clock_in(armv7m, "refclk", mms->refclk);
qdev_prop_set_string(armv7m, "cpu-type", machine->cpu_type);
qdev_prop_set_bit(armv7m, "enable-bitband", true);
object_property_set_link(OBJECT(&mms->armv7m), "memory",
@@ -424,8 +439,6 @@ static void mps2_common_init(MachineState *machine)
qdev_get_gpio_in(armv7m,
mmc->fpga_type == FPGA_AN511 ? 47 : 13));
- system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
-
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
0x400000);
}
diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c
index 5cfe7caf83..b5fe9f364d 100644
--- a/hw/arm/msf2-soc.c
+++ b/hw/arm/msf2-soc.c
@@ -29,6 +29,7 @@
#include "hw/char/serial.h"
#include "hw/arm/msf2-soc.h"
#include "hw/misc/unimp.h"
+#include "hw/qdev-clock.h"
#include "sysemu/sysemu.h"
#define MSF2_TIMER_BASE 0x40004000
@@ -73,6 +74,9 @@ static void m2sxxx_soc_initfn(Object *obj)
}
object_initialize_child(obj, "emac", &s->emac, TYPE_MSS_EMAC);
+
+ s->m3clk = qdev_init_clock_in(DEVICE(obj), "m3clk", NULL, NULL, 0);
+ s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", NULL, NULL, 0);
}
static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -83,11 +87,34 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
int i;
MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *nvm = g_new(MemoryRegion, 1);
- MemoryRegion *nvm_alias = g_new(MemoryRegion, 1);
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- memory_region_init_rom(nvm, OBJECT(dev_soc), "MSF2.eNVM", s->envm_size,
+ if (!clock_has_source(s->m3clk)) {
+ error_setg(errp, "m3clk must be wired up by the board code");
+ return;
+ }
+
+ /*
+ * We use s->refclk internally and only define it with qdev_init_clock_in()
+ * so it is correctly parented and not leaked on an init/deinit; it is not
+ * intended as an externally exposed clock.
+ */
+ if (clock_has_source(s->refclk)) {
+ error_setg(errp, "refclk must not be wired up by the board code");
+ return;
+ }
+
+ /*
+ * TODO: ideally we should model the SoC SYSTICK_CR register at 0xe0042038,
+ * which allows the guest to program the divisor between the m3clk and
+ * the systick refclk to either /4, /8, /16 or /32, as well as setting
+ * the value the guest can read in the STCALIB register. Currently we
+ * implement the divisor as a fixed /32, which matches the reset value
+ * of SYSTICK_CR.
+ */
+ clock_set_mul_div(s->refclk, 32, 1);
+ clock_set_source(s->refclk, s->m3clk);
+
+ memory_region_init_rom(&s->nvm, OBJECT(dev_soc), "MSF2.eNVM", s->envm_size,
&error_fatal);
/*
* On power-on, the eNVM region 0x60000000 is automatically
@@ -95,34 +122,28 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
* start address (0x0). We do not support remapping other eNVM,
* eSRAM and DDR regions by guest(via Sysreg) currently.
*/
- memory_region_init_alias(nvm_alias, OBJECT(dev_soc), "MSF2.eNVM", nvm, 0,
- s->envm_size);
+ memory_region_init_alias(&s->nvm_alias, OBJECT(dev_soc), "MSF2.eNVM",
+ &s->nvm, 0, s->envm_size);
- memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, nvm);
- memory_region_add_subregion(system_memory, 0, nvm_alias);
+ memory_region_add_subregion(system_memory, ENVM_BASE_ADDRESS, &s->nvm);
+ memory_region_add_subregion(system_memory, 0, &s->nvm_alias);
- memory_region_init_ram(sram, NULL, "MSF2.eSRAM", s->esram_size,
+ memory_region_init_ram(&s->sram, NULL, "MSF2.eSRAM", s->esram_size,
&error_fatal);
- memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
armv7m = DEVICE(&s->armv7m);
qdev_prop_set_uint32(armv7m, "num-irq", 81);
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk", s->m3clk);
+ qdev_connect_clock_in(armv7m, "refclk", s->refclk);
object_property_set_link(OBJECT(&s->armv7m), "memory",
OBJECT(get_system_memory()), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
return;
}
- if (!s->m3clk) {
- error_setg(errp, "Invalid m3clk value");
- error_append_hint(errp, "m3clk can not be zero\n");
- return;
- }
-
- system_clock_scale = NANOSECONDS_PER_SECOND / s->m3clk;
-
for (i = 0; i < MSF2_NUM_UARTS; i++) {
if (serial_hd(i)) {
serial_mm_init(get_system_memory(), uart_addr[i], 2,
@@ -132,8 +153,13 @@ static void m2sxxx_soc_realize(DeviceState *dev_soc, Error **errp)
}
dev = DEVICE(&s->timer);
- /* APB0 clock is the timer input clock */
- qdev_prop_set_uint32(dev, "clock-frequency", s->m3clk / s->apb0div);
+ /*
+ * APB0 clock is the timer input clock.
+ * TODO: ideally the MSF2 timer device should use a Clock rather than a
+ * clock-frequency integer property.
+ */
+ qdev_prop_set_uint32(dev, "clock-frequency",
+ clock_get_hz(s->m3clk) / s->apb0div);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) {
return;
}
@@ -210,8 +236,6 @@ static Property m2sxxx_soc_properties[] = {
DEFINE_PROP_UINT64("eNVM-size", MSF2State, envm_size, MSF2_ENVM_MAX_SIZE),
DEFINE_PROP_UINT64("eSRAM-size", MSF2State, esram_size,
MSF2_ESRAM_MAX_SIZE),
- /* Libero GUI shows 100Mhz as default for clocks */
- DEFINE_PROP_UINT32("m3clk", MSF2State, m3clk, 100 * 1000000),
/* default divisors in Libero GUI */
DEFINE_PROP_UINT8("apb0div", MSF2State, apb0div, 2),
DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2),
diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c
index 343ec977c0..396e8b9913 100644
--- a/hw/arm/msf2-som.c
+++ b/hw/arm/msf2-som.c
@@ -29,6 +29,7 @@
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "hw/arm/boot.h"
+#include "hw/qdev-clock.h"
#include "exec/address-spaces.h"
#include "hw/arm/msf2-soc.h"
@@ -49,6 +50,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
BusState *spi_bus;
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ddr = g_new(MemoryRegion, 1);
+ Clock *m3clk;
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
error_report("This board can only be used with CPU %s",
@@ -72,7 +74,10 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
* in Libero. CPU clock is divided by APB0 and APB1 divisors for
* peripherals. Emcraft's SoM kit comes with these settings by default.
*/
- qdev_prop_set_uint32(dev, "m3clk", 142 * 1000000);
+ /* This clock doesn't need migration because it is fixed-frequency */
+ m3clk = clock_new(OBJECT(machine), "m3clk");
+ clock_set_hz(m3clk, 142 * 1000000);
+ qdev_connect_clock_in(dev, "m3clk", m3clk);
qdev_prop_set_uint32(dev, "apb0div", 2);
qdev_prop_set_uint32(dev, "apb1div", 2);
diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
index 1733b71507..3365da11bf 100644
--- a/hw/arm/netduino2.c
+++ b/hw/arm/netduino2.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "qemu/error-report.h"
#include "hw/arm/stm32f205_soc.h"
#include "hw/arm/boot.h"
@@ -36,16 +37,15 @@
static void netduino2_init(MachineState *machine)
{
DeviceState *dev;
+ Clock *sysclk;
- /*
- * TODO: ideally we would model the SoC RCC and let it handle
- * system_clock_scale, including its ability to define different
- * possible SYSCLK sources.
- */
- system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
+ /* This clock doesn't need migration because it is fixed-frequency */
+ sysclk = clock_new(OBJECT(machine), "SYSCLK");
+ clock_set_hz(sysclk, SYSCLK_FRQ);
dev = qdev_new(TYPE_STM32F205_SOC);
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
+ qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
diff --git a/hw/arm/netduinoplus2.c b/hw/arm/netduinoplus2.c
index d3ad7a2b67..76cea8e489 100644
--- a/hw/arm/netduinoplus2.c
+++ b/hw/arm/netduinoplus2.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "qemu/error-report.h"
#include "hw/arm/stm32f405_soc.h"
#include "hw/arm/boot.h"
@@ -36,16 +37,15 @@
static void netduinoplus2_init(MachineState *machine)
{
DeviceState *dev;
+ Clock *sysclk;
- /*
- * TODO: ideally we would model the SoC RCC and let it handle
- * system_clock_scale, including its ability to define different
- * possible SYSCLK sources.
- */
- system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
+ /* This clock doesn't need migration because it is fixed-frequency */
+ sysclk = clock_new(OBJECT(machine), "SYSCLK");
+ clock_set_hz(sysclk, SYSCLK_FRQ);
dev = qdev_new(TYPE_STM32F405_SOC);
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
+ qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
armv7m_load_kernel(ARM_CPU(first_cpu),
diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c
index 9407c2f268..34da0d62f0 100644
--- a/hw/arm/nrf51_soc.c
+++ b/hw/arm/nrf51_soc.c
@@ -12,6 +12,7 @@
#include "qapi/error.h"
#include "hw/arm/boot.h"
#include "hw/sysbus.h"
+#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
#include "qemu/log.h"
@@ -66,7 +67,22 @@ static void nrf51_soc_realize(DeviceState *dev_soc, Error **errp)
return;
}
- system_clock_scale = NANOSECONDS_PER_SECOND / HCLK_FRQ;
+ /*
+ * HCLK on this SoC is fixed, so we set up sysclk ourselves and
+ * the board shouldn't connect it.
+ */
+ if (clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must not be wired up by the board code");
+ return;
+ }
+ /* This clock doesn't need migration because it is fixed-frequency */
+ clock_set_hz(s->sysclk, HCLK_FRQ);
+ qdev_connect_clock_in(DEVICE(&s->cpu), "cpuclk", s->sysclk);
+ /*
+ * This SoC has no systick device, so don't connect refclk.
+ * TODO: model the lack of systick (currently the armv7m object
+ * will always provide one).
+ */
object_property_set_link(OBJECT(&s->cpu), "memory", OBJECT(&s->container),
&error_abort);
@@ -191,6 +207,8 @@ static void nrf51_soc_init(Object *obj)
TYPE_NRF51_TIMER);
}
+
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
}
static Property nrf51_soc_properties[] = {
diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c
index 0ada91c05e..146d35382b 100644
--- a/hw/arm/raspi.c
+++ b/hw/arm/raspi.c
@@ -340,7 +340,6 @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
- mc->alias = "raspi2";
rmc->board_rev = 0xa21041;
raspi_machine_class_common_init(mc, rmc->board_rev);
};
@@ -360,7 +359,6 @@ static void raspi3b_machine_class_init(ObjectClass *oc, void *data)
MachineClass *mc = MACHINE_CLASS(oc);
RaspiMachineClass *rmc = RASPI_MACHINE_CLASS(oc);
- mc->alias = "raspi3";
rmc->board_rev = 0xa02082;
raspi_machine_class_common_init(mc, rmc->board_rev);
};
diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c
index ad48cf2605..78827ace6b 100644
--- a/hw/arm/stellaris.c
+++ b/hw/arm/stellaris.c
@@ -26,6 +26,7 @@
#include "hw/watchdog/cmsdk-apb-watchdog.h"
#include "migration/vmstate.h"
#include "hw/misc/unimp.h"
+#include "hw/timer/stellaris-gptm.h"
#include "hw/qdev-clock.h"
#include "qom/object.h"
@@ -55,306 +56,6 @@ typedef const struct {
uint32_t peripherals;
} stellaris_board_info;
-/* General purpose timer module. */
-
-#define TYPE_STELLARIS_GPTM "stellaris-gptm"
-OBJECT_DECLARE_SIMPLE_TYPE(gptm_state, STELLARIS_GPTM)
-
-struct gptm_state {
- SysBusDevice parent_obj;
-
- MemoryRegion iomem;
- uint32_t config;
- uint32_t mode[2];
- uint32_t control;
- uint32_t state;
- uint32_t mask;
- uint32_t load[2];
- uint32_t match[2];
- uint32_t prescale[2];
- uint32_t match_prescale[2];
- uint32_t rtc;
- int64_t tick[2];
- struct gptm_state *opaque[2];
- QEMUTimer *timer[2];
- /* The timers have an alternate output used to trigger the ADC. */
- qemu_irq trigger;
- qemu_irq irq;
-};
-
-static void gptm_update_irq(gptm_state *s)
-{
- int level;
- level = (s->state & s->mask) != 0;
- qemu_set_irq(s->irq, level);
-}
-
-static void gptm_stop(gptm_state *s, int n)
-{
- timer_del(s->timer[n]);
-}
-
-static void gptm_reload(gptm_state *s, int n, int reset)
-{
- int64_t tick;
- if (reset)
- tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- else
- tick = s->tick[n];
-
- if (s->config == 0) {
- /* 32-bit CountDown. */
- uint32_t count;
- count = s->load[0] | (s->load[1] << 16);
- tick += (int64_t)count * system_clock_scale;
- } else if (s->config == 1) {
- /* 32-bit RTC. 1Hz tick. */
- tick += NANOSECONDS_PER_SECOND;
- } else if (s->mode[n] == 0xa) {
- /* PWM mode. Not implemented. */
- } else {
- qemu_log_mask(LOG_UNIMP,
- "GPTM: 16-bit timer mode unimplemented: 0x%x\n",
- s->mode[n]);
- return;
- }
- s->tick[n] = tick;
- timer_mod(s->timer[n], tick);
-}
-
-static void gptm_tick(void *opaque)
-{
- gptm_state **p = (gptm_state **)opaque;
- gptm_state *s;
- int n;
-
- s = *p;
- n = p - s->opaque;
- if (s->config == 0) {
- s->state |= 1;
- if ((s->control & 0x20)) {
- /* Output trigger. */
- qemu_irq_pulse(s->trigger);
- }
- if (s->mode[0] & 1) {
- /* One-shot. */
- s->control &= ~1;
- } else {
- /* Periodic. */
- gptm_reload(s, 0, 0);
- }
- } else if (s->config == 1) {
- /* RTC. */
- uint32_t match;
- s->rtc++;
- match = s->match[0] | (s->match[1] << 16);
- if (s->rtc > match)
- s->rtc = 0;
- if (s->rtc == 0) {
- s->state |= 8;
- }
- gptm_reload(s, 0, 0);
- } else if (s->mode[n] == 0xa) {
- /* PWM mode. Not implemented. */
- } else {
- qemu_log_mask(LOG_UNIMP,
- "GPTM: 16-bit timer mode unimplemented: 0x%x\n",
- s->mode[n]);
- }
- gptm_update_irq(s);
-}
-
-static uint64_t gptm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- gptm_state *s = (gptm_state *)opaque;
-
- switch (offset) {
- case 0x00: /* CFG */
- return s->config;
- case 0x04: /* TAMR */
- return s->mode[0];
- case 0x08: /* TBMR */
- return s->mode[1];
- case 0x0c: /* CTL */
- return s->control;
- case 0x18: /* IMR */
- return s->mask;
- case 0x1c: /* RIS */
- return s->state;
- case 0x20: /* MIS */
- return s->state & s->mask;
- case 0x24: /* CR */
- return 0;
- case 0x28: /* TAILR */
- return s->load[0] | ((s->config < 4) ? (s->load[1] << 16) : 0);
- case 0x2c: /* TBILR */
- return s->load[1];
- case 0x30: /* TAMARCHR */
- return s->match[0] | ((s->config < 4) ? (s->match[1] << 16) : 0);
- case 0x34: /* TBMATCHR */
- return s->match[1];
- case 0x38: /* TAPR */
- return s->prescale[0];
- case 0x3c: /* TBPR */
- return s->prescale[1];
- case 0x40: /* TAPMR */
- return s->match_prescale[0];
- case 0x44: /* TBPMR */
- return s->match_prescale[1];
- case 0x48: /* TAR */
- if (s->config == 1) {
- return s->rtc;
- }
- qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TAR but timer read not supported\n");
- return 0;
- case 0x4c: /* TBR */
- qemu_log_mask(LOG_UNIMP,
- "GPTM: read of TBR but timer read not supported\n");
- return 0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "GPTM: read at bad offset 0x02%" HWADDR_PRIx "\n",
- offset);
- return 0;
- }
-}
-
-static void gptm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- gptm_state *s = (gptm_state *)opaque;
- uint32_t oldval;
-
- /* The timers should be disabled before changing the configuration.
- We take advantage of this and defer everything until the timer
- is enabled. */
- switch (offset) {
- case 0x00: /* CFG */
- s->config = value;
- break;
- case 0x04: /* TAMR */
- s->mode[0] = value;
- break;
- case 0x08: /* TBMR */
- s->mode[1] = value;
- break;
- case 0x0c: /* CTL */
- oldval = s->control;
- s->control = value;
- /* TODO: Implement pause. */
- if ((oldval ^ value) & 1) {
- if (value & 1) {
- gptm_reload(s, 0, 1);
- } else {
- gptm_stop(s, 0);
- }
- }
- if (((oldval ^ value) & 0x100) && s->config >= 4) {
- if (value & 0x100) {
- gptm_reload(s, 1, 1);
- } else {
- gptm_stop(s, 1);
- }
- }
- break;
- case 0x18: /* IMR */
- s->mask = value & 0x77;
- gptm_update_irq(s);
- break;
- case 0x24: /* CR */
- s->state &= ~value;
- break;
- case 0x28: /* TAILR */
- s->load[0] = value & 0xffff;
- if (s->config < 4) {
- s->load[1] = value >> 16;
- }
- break;
- case 0x2c: /* TBILR */
- s->load[1] = value & 0xffff;
- break;
- case 0x30: /* TAMARCHR */
- s->match[0] = value & 0xffff;
- if (s->config < 4) {
- s->match[1] = value >> 16;
- }
- break;
- case 0x34: /* TBMATCHR */
- s->match[1] = value >> 16;
- break;
- case 0x38: /* TAPR */
- s->prescale[0] = value;
- break;
- case 0x3c: /* TBPR */
- s->prescale[1] = value;
- break;
- case 0x40: /* TAPMR */
- s->match_prescale[0] = value;
- break;
- case 0x44: /* TBPMR */
- s->match_prescale[0] = value;
- break;
- default:
- qemu_log_mask(LOG_GUEST_ERROR,
- "GPTM: write at bad offset 0x02%" HWADDR_PRIx "\n",
- offset);
- }
- gptm_update_irq(s);
-}
-
-static const MemoryRegionOps gptm_ops = {
- .read = gptm_read,
- .write = gptm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_stellaris_gptm = {
- .name = "stellaris_gptm",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(config, gptm_state),
- VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
- VMSTATE_UINT32(control, gptm_state),
- VMSTATE_UINT32(state, gptm_state),
- VMSTATE_UINT32(mask, gptm_state),
- VMSTATE_UNUSED(8),
- VMSTATE_UINT32_ARRAY(load, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(match, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(prescale, gptm_state, 2),
- VMSTATE_UINT32_ARRAY(match_prescale, gptm_state, 2),
- VMSTATE_UINT32(rtc, gptm_state),
- VMSTATE_INT64_ARRAY(tick, gptm_state, 2),
- VMSTATE_TIMER_PTR_ARRAY(timer, gptm_state, 2),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void stellaris_gptm_init(Object *obj)
-{
- DeviceState *dev = DEVICE(obj);
- gptm_state *s = STELLARIS_GPTM(obj);
- SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
-
- sysbus_init_irq(sbd, &s->irq);
- qdev_init_gpio_out(dev, &s->trigger, 1);
-
- memory_region_init_io(&s->iomem, obj, &gptm_ops, s,
- "gptm", 0x1000);
- sysbus_init_mmio(sbd, &s->iomem);
-
- s->opaque[0] = s->opaque[1] = s;
-}
-
-static void stellaris_gptm_realize(DeviceState *dev, Error **errp)
-{
- gptm_state *s = STELLARIS_GPTM(dev);
- s->timer[0] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[0]);
- s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]);
-}
-
/* System controller. */
#define TYPE_STELLARIS_SYS "stellaris-sys"
@@ -562,17 +263,18 @@ static bool ssys_use_rcc2(ssys_state *s)
*/
static void ssys_calculate_system_clock(ssys_state *s, bool propagate_clock)
{
+ int period_ns;
/*
* SYSDIV field specifies divisor: 0 == /1, 1 == /2, etc. Input
* clock is 200MHz, which is a period of 5 ns. Dividing the clock
* frequency by X is the same as multiplying the period by X.
*/
if (ssys_use_rcc2(s)) {
- system_clock_scale = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
+ period_ns = 5 * (((s->rcc2 >> 23) & 0x3f) + 1);
} else {
- system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
+ period_ns = 5 * (((s->rcc >> 23) & 0xf) + 1);
}
- clock_set_ns(s->sysclk, system_clock_scale);
+ clock_set_ns(s->sysclk, period_ns);
if (propagate_clock) {
clock_propagate(s->sysclk);
}
@@ -755,33 +457,6 @@ static void stellaris_sys_instance_init(Object *obj)
s->sysclk = qdev_init_clock_out(DEVICE(s), "SYSCLK");
}
-static DeviceState *stellaris_sys_init(uint32_t base, qemu_irq irq,
- stellaris_board_info *board,
- uint8_t *macaddr)
-{
- DeviceState *dev = qdev_new(TYPE_STELLARIS_SYS);
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-
- /* Most devices come preprogrammed with a MAC address in the user data. */
- qdev_prop_set_uint32(dev, "user0",
- macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16));
- qdev_prop_set_uint32(dev, "user1",
- macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16));
- qdev_prop_set_uint32(dev, "did0", board->did0);
- qdev_prop_set_uint32(dev, "did1", board->did1);
- qdev_prop_set_uint32(dev, "dc0", board->dc0);
- qdev_prop_set_uint32(dev, "dc1", board->dc1);
- qdev_prop_set_uint32(dev, "dc2", board->dc2);
- qdev_prop_set_uint32(dev, "dc3", board->dc3);
- qdev_prop_set_uint32(dev, "dc4", board->dc4);
-
- sysbus_realize_and_unref(sbd, &error_fatal);
- sysbus_mmio_map(sbd, 0, base);
- sysbus_connect_irq(sbd, 0, irq);
-
- return dev;
-}
-
/* I2C controller. */
#define TYPE_STELLARIS_I2C "stellaris-i2c"
@@ -1349,6 +1024,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
DeviceState *ssys_dev;
int i;
int j;
+ const uint8_t *macaddr;
MemoryRegion *sram = g_new(MemoryRegion, 1);
MemoryRegion *flash = g_new(MemoryRegion, 1);
@@ -1366,15 +1042,42 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
&error_fatal);
memory_region_add_subregion(system_memory, 0x20000000, sram);
+ /*
+ * Create the system-registers object early, because we will
+ * need its sysclk output.
+ */
+ ssys_dev = qdev_new(TYPE_STELLARIS_SYS);
+ /* Most devices come preprogrammed with a MAC address in the user data. */
+ macaddr = nd_table[0].macaddr.a;
+ qdev_prop_set_uint32(ssys_dev, "user0",
+ macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16));
+ qdev_prop_set_uint32(ssys_dev, "user1",
+ macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16));
+ qdev_prop_set_uint32(ssys_dev, "did0", board->did0);
+ qdev_prop_set_uint32(ssys_dev, "did1", board->did1);
+ qdev_prop_set_uint32(ssys_dev, "dc0", board->dc0);
+ qdev_prop_set_uint32(ssys_dev, "dc1", board->dc1);
+ qdev_prop_set_uint32(ssys_dev, "dc2", board->dc2);
+ qdev_prop_set_uint32(ssys_dev, "dc3", board->dc3);
+ qdev_prop_set_uint32(ssys_dev, "dc4", board->dc4);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ssys_dev), &error_fatal);
+
nvic = qdev_new(TYPE_ARMV7M);
qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type);
qdev_prop_set_bit(nvic, "enable-bitband", true);
+ qdev_connect_clock_in(nvic, "cpuclk",
+ qdev_get_clock_out(ssys_dev, "SYSCLK"));
+ /* This SoC does not connect the systick reference clock */
object_property_set_link(OBJECT(nvic), "memory",
OBJECT(get_system_memory()), &error_abort);
/* This will exit with an error if the user passed us a bad cpu_type */
sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal);
+ /* Now we can wire up the IRQ and MMIO of the system registers */
+ sysbus_mmio_map(SYS_BUS_DEVICE(ssys_dev), 0, 0x400fe000);
+ sysbus_connect_irq(SYS_BUS_DEVICE(ssys_dev), 0, qdev_get_gpio_in(nvic, 28));
+
if (board->dc1 & (1 << 16)) {
dev = sysbus_create_varargs(TYPE_STELLARIS_ADC, 0x40038000,
qdev_get_gpio_in(nvic, 14),
@@ -1388,19 +1091,21 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
}
for (i = 0; i < 4; i++) {
if (board->dc2 & (0x10000 << i)) {
- dev = sysbus_create_simple(TYPE_STELLARIS_GPTM,
- 0x40030000 + i * 0x1000,
- qdev_get_gpio_in(nvic, timer_irq[i]));
+ SysBusDevice *sbd;
+
+ dev = qdev_new(TYPE_STELLARIS_GPTM);
+ sbd = SYS_BUS_DEVICE(dev);
+ qdev_connect_clock_in(dev, "clk",
+ qdev_get_clock_out(ssys_dev, "SYSCLK"));
+ sysbus_realize_and_unref(sbd, &error_fatal);
+ sysbus_mmio_map(sbd, 0, 0x40030000 + i * 0x1000);
+ sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(nvic, timer_irq[i]));
/* TODO: This is incorrect, but we get away with it because
the ADC output is only ever pulsed. */
qdev_connect_gpio_out(dev, 0, adc);
}
}
- ssys_dev = stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
- board, nd_table[0].macaddr.a);
-
-
if (board->dc1 & (1 << 3)) { /* watchdog present */
dev = qdev_new(TYPE_LUMINARY_WATCHDOG);
@@ -1642,22 +1347,6 @@ static const TypeInfo stellaris_i2c_info = {
.class_init = stellaris_i2c_class_init,
};
-static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- dc->vmsd = &vmstate_stellaris_gptm;
- dc->realize = stellaris_gptm_realize;
-}
-
-static const TypeInfo stellaris_gptm_info = {
- .name = TYPE_STELLARIS_GPTM,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(gptm_state),
- .instance_init = stellaris_gptm_init,
- .class_init = stellaris_gptm_class_init,
-};
-
static void stellaris_adc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -1696,7 +1385,6 @@ static const TypeInfo stellaris_sys_info = {
static void stellaris_register_types(void)
{
type_register_static(&stellaris_i2c_info);
- type_register_static(&stellaris_gptm_info);
type_register_static(&stellaris_adc_info);
type_register_static(&stellaris_sys_info);
}
diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c
index 0c4a5c6645..f7b344ba9f 100644
--- a/hw/arm/stm32f100_soc.c
+++ b/hw/arm/stm32f100_soc.c
@@ -30,6 +30,7 @@
#include "exec/address-spaces.h"
#include "hw/arm/stm32f100_soc.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
#include "sysemu/sysemu.h"
@@ -57,6 +58,9 @@ static void stm32f100_soc_initfn(Object *obj)
for (i = 0; i < STM_NUM_SPIS; i++) {
object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI);
}
+
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+ s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
}
static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -67,31 +71,54 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp)
int i;
MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
+
+ /*
+ * We use s->refclk internally and only define it with qdev_init_clock_in()
+ * so it is correctly parented and not leaked on an init/deinit; it is not
+ * intended as an externally exposed clock.
+ */
+ if (clock_has_source(s->refclk)) {
+ error_setg(errp, "refclk clock must not be wired up by the board code");
+ return;
+ }
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ /*
+ * TODO: ideally we should model the SoC RCC and its ability to
+ * change the sysclk frequency and define different sysclk sources.
+ */
+
+ /* The refclk always runs at frequency HCLK / 8 */
+ clock_set_mul_div(s->refclk, 8, 1);
+ clock_set_source(s->refclk, s->sysclk);
/*
* Init flash region
* Flash starts at 0x08000000 and then is aliased to boot memory at 0x0
*/
- memory_region_init_rom(flash, OBJECT(dev_soc), "STM32F100.flash",
+ memory_region_init_rom(&s->flash, OBJECT(dev_soc), "STM32F100.flash",
FLASH_SIZE, &error_fatal);
- memory_region_init_alias(flash_alias, OBJECT(dev_soc),
- "STM32F100.flash.alias", flash, 0, FLASH_SIZE);
- memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
- memory_region_add_subregion(system_memory, 0, flash_alias);
+ memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc),
+ "STM32F100.flash.alias", &s->flash, 0, FLASH_SIZE);
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
+ memory_region_add_subregion(system_memory, 0, &s->flash_alias);
/* Init SRAM region */
- memory_region_init_ram(sram, NULL, "STM32F100.sram", SRAM_SIZE,
+ memory_region_init_ram(&s->sram, NULL, "STM32F100.sram", SRAM_SIZE,
&error_fatal);
- memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
/* Init ARMv7m */
armv7m = DEVICE(&s->armv7m);
qdev_prop_set_uint32(armv7m, "num-irq", 61);
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ qdev_connect_clock_in(armv7m, "refclk", s->refclk);
object_property_set_link(OBJECT(&s->armv7m), "memory",
OBJECT(get_system_memory()), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
index 9cd41bf56d..c6b75a381d 100644
--- a/hw/arm/stm32f205_soc.c
+++ b/hw/arm/stm32f205_soc.c
@@ -29,6 +29,7 @@
#include "exec/address-spaces.h"
#include "hw/arm/stm32f205_soc.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "sysemu/sysemu.h"
/* At the moment only Timer 2 to 5 are modelled */
@@ -74,6 +75,9 @@ static void stm32f205_soc_initfn(Object *obj)
for (i = 0; i < STM_NUM_SPIS; i++) {
object_initialize_child(obj, "spi[*]", &s->spi[i], TYPE_STM32F2XX_SPI);
}
+
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+ s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
}
static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -84,26 +88,49 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
int i;
MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *sram = g_new(MemoryRegion, 1);
- MemoryRegion *flash = g_new(MemoryRegion, 1);
- MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
- memory_region_init_rom(flash, OBJECT(dev_soc), "STM32F205.flash",
+ /*
+ * We use s->refclk internally and only define it with qdev_init_clock_in()
+ * so it is correctly parented and not leaked on an init/deinit; it is not
+ * intended as an externally exposed clock.
+ */
+ if (clock_has_source(s->refclk)) {
+ error_setg(errp, "refclk clock must not be wired up by the board code");
+ return;
+ }
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ /*
+ * TODO: ideally we should model the SoC RCC and its ability to
+ * change the sysclk frequency and define different sysclk sources.
+ */
+
+ /* The refclk always runs at frequency HCLK / 8 */
+ clock_set_mul_div(s->refclk, 8, 1);
+ clock_set_source(s->refclk, s->sysclk);
+
+ memory_region_init_rom(&s->flash, OBJECT(dev_soc), "STM32F205.flash",
FLASH_SIZE, &error_fatal);
- memory_region_init_alias(flash_alias, OBJECT(dev_soc),
- "STM32F205.flash.alias", flash, 0, FLASH_SIZE);
+ memory_region_init_alias(&s->flash_alias, OBJECT(dev_soc),
+ "STM32F205.flash.alias", &s->flash, 0, FLASH_SIZE);
- memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
- memory_region_add_subregion(system_memory, 0, flash_alias);
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
+ memory_region_add_subregion(system_memory, 0, &s->flash_alias);
- memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE,
+ memory_region_init_ram(&s->sram, NULL, "STM32F205.sram", SRAM_SIZE,
&error_fatal);
- memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
armv7m = DEVICE(&s->armv7m);
qdev_prop_set_uint32(armv7m, "num-irq", 96);
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ qdev_connect_clock_in(armv7m, "refclk", s->refclk);
object_property_set_link(OBJECT(&s->armv7m), "memory",
OBJECT(get_system_memory()), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c
index cb04c11198..0019b7f478 100644
--- a/hw/arm/stm32f405_soc.c
+++ b/hw/arm/stm32f405_soc.c
@@ -28,6 +28,7 @@
#include "exec/address-spaces.h"
#include "sysemu/sysemu.h"
#include "hw/arm/stm32f405_soc.h"
+#include "hw/qdev-clock.h"
#include "hw/misc/unimp.h"
#define SYSCFG_ADD 0x40013800
@@ -80,6 +81,9 @@ static void stm32f405_soc_initfn(Object *obj)
}
object_initialize_child(obj, "exti", &s->exti, TYPE_STM32F4XX_EXTI);
+
+ s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
+ s->refclk = qdev_init_clock_in(DEVICE(s), "refclk", NULL, NULL, 0);
}
static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
@@ -91,6 +95,30 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
Error *err = NULL;
int i;
+ /*
+ * We use s->refclk internally and only define it with qdev_init_clock_in()
+ * so it is correctly parented and not leaked on an init/deinit; it is not
+ * intended as an externally exposed clock.
+ */
+ if (clock_has_source(s->refclk)) {
+ error_setg(errp, "refclk clock must not be wired up by the board code");
+ return;
+ }
+
+ if (!clock_has_source(s->sysclk)) {
+ error_setg(errp, "sysclk clock must be wired up by the board code");
+ return;
+ }
+
+ /*
+ * TODO: ideally we should model the SoC RCC and its ability to
+ * change the sysclk frequency and define different sysclk sources.
+ */
+
+ /* The refclk always runs at frequency HCLK / 8 */
+ clock_set_mul_div(s->refclk, 8, 1);
+ clock_set_source(s->refclk, s->sysclk);
+
memory_region_init_rom(&s->flash, OBJECT(dev_soc), "STM32F405.flash",
FLASH_SIZE, &err);
if (err != NULL) {
@@ -116,6 +144,8 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp)
qdev_prop_set_uint32(armv7m, "num-irq", 96);
qdev_prop_set_string(armv7m, "cpu-type", s->cpu_type);
qdev_prop_set_bit(armv7m, "enable-bitband", true);
+ qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
+ qdev_connect_clock_in(armv7m, "refclk", s->refclk);
object_property_set_link(OBJECT(&s->armv7m), "memory",
OBJECT(system_memory), &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
diff --git a/hw/arm/stm32vldiscovery.c b/hw/arm/stm32vldiscovery.c
index 7e8191ebf5..04036da3ee 100644
--- a/hw/arm/stm32vldiscovery.c
+++ b/hw/arm/stm32vldiscovery.c
@@ -27,6 +27,7 @@
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
+#include "hw/qdev-clock.h"
#include "qemu/error-report.h"
#include "hw/arm/stm32f100_soc.h"
#include "hw/arm/boot.h"
@@ -39,16 +40,15 @@
static void stm32vldiscovery_init(MachineState *machine)
{
DeviceState *dev;
+ Clock *sysclk;
- /*
- * TODO: ideally we would model the SoC RCC and let it handle
- * system_clock_scale, including its ability to define different
- * possible SYSCLK sources.
- */
- system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
+ /* This clock doesn't need migration because it is fixed-frequency */
+ sysclk = clock_new(OBJECT(machine), "SYSCLK");
+ clock_set_hz(sysclk, SYSCLK_FRQ);
dev = qdev_new(TYPE_STM32F100_SOC);
qdev_prop_set_string(dev, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m3"));
+ qdev_connect_clock_in(dev, "sysclk", sysclk);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
armv7m_load_kernel(ARM_CPU(first_cpu),
@@ -63,4 +63,3 @@ static void stm32vldiscovery_machine_init(MachineClass *mc)
}
DEFINE_MACHINE("stm32vldiscovery", stm32vldiscovery_machine_init)
-
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 86c8a4ca3d..73e9c6bb7c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -200,6 +200,7 @@ static const char *valid_cpus[] = {
ARM_CPU_TYPE_NAME("cortex-a53"),
ARM_CPU_TYPE_NAME("cortex-a57"),
ARM_CPU_TYPE_NAME("cortex-a72"),
+ ARM_CPU_TYPE_NAME("a64fx"),
ARM_CPU_TYPE_NAME("host"),
ARM_CPU_TYPE_NAME("max"),
};
@@ -2783,10 +2784,17 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+static void virt_machine_6_2_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(6, 2)
+
static void virt_machine_6_1_options(MachineClass *mc)
{
+ virt_machine_6_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(6, 1)
+DEFINE_VIRT_MACHINE(6, 1)
static void virt_machine_6_0_options(MachineClass *mc)
{