mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210901' into staging
* Refactor M-profile systick to use Clocks instead of system_clock_scale global * clock: Provide builtin multiplier/divider * Add A64FX processor model * Enable MVE emulation in Cortex-M55 * hw: Add compat machines for 6.2 * hw/intc/arm_gicv3: Replace mis-used MEMTX_* constants by booleans * hw/arm/raspi: Remove deprecated raspi2/raspi3 aliases # gpg: Signature made Wed 01 Sep 2021 11:35:57 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210901: (51 commits) arm: Remove system_clock_scale global hw/timer/stellaris-gptm: Use Clock input instead of system_clock_scale hw/arm/stellaris: Split stellaris-gptm into its own file hw/arm/stellaris: Fix code style issues in GPTM code hw/timer/armv7m_systick: Use clock inputs instead of system_clock_scale hw/arm/msf2-soc: Wire up refclk hw/arm/msf2: Use Clock input to MSF2_SOC instead of m3clk property hw/arm/msf2_soc: Don't allocate separate MemoryRegions hw/arm/stellaris: Wire sysclk up to armv7m hw/arm/stellaris: split stellaris_sys_init() hw/arm/nrf51: Wire up sysclk hw/arm/stm32vldiscovery: Delete trailing blank line hw/arm/stm32f405: Wire up sysclk and refclk hw/arm/stm32f205: Wire up sysclk and refclk hw/arm/stm32f100: Wire up sysclk and refclk hw/arm: Don't allocate separate MemoryRegions in stm32 SoC realize clock: Provide builtin multiplier/divider hw/arm/mps2.c: Connect up armv7m clocks armsse: Wire up systick cpuclk clock hw/arm/armv7m: Create input clocks ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -617,6 +617,7 @@ F: hw/intc/gic_internal.h
|
||||
F: hw/misc/a9scu.c
|
||||
F: hw/misc/arm11scu.c
|
||||
F: hw/misc/arm_l2x0.c
|
||||
F: hw/misc/armv7m_ras.c
|
||||
F: hw/timer/a9gtimer*
|
||||
F: hw/timer/arm*
|
||||
F: include/hw/arm/arm*.h
|
||||
@@ -626,6 +627,7 @@ F: include/hw/misc/arm11scu.h
|
||||
F: include/hw/timer/a9gtimer.h
|
||||
F: include/hw/timer/arm_mptimer.h
|
||||
F: include/hw/timer/armv7m_systick.h
|
||||
F: include/hw/misc/armv7m_ras.h
|
||||
F: tests/qtest/test-arm-mptimer.c
|
||||
|
||||
Exynos
|
||||
|
||||
@@ -207,13 +207,6 @@ this CPU is also deprecated.
|
||||
System emulator machines
|
||||
------------------------
|
||||
|
||||
Raspberry Pi ``raspi2`` and ``raspi3`` machines (since 5.2)
|
||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Raspberry Pi machines come in various models (A, A+, B, B+). To be able
|
||||
to distinguish which model QEMU is implementing, the ``raspi2`` and ``raspi3``
|
||||
machines have been renamed ``raspi2b`` and ``raspi3b``.
|
||||
|
||||
Aspeed ``swift-bmc`` machine (since 6.1)
|
||||
''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -574,6 +574,13 @@ This machine has been renamed ``fuloong2e``.
|
||||
These machine types were very old and likely could not be used for live
|
||||
migration from old QEMU versions anymore. Use a newer machine type instead.
|
||||
|
||||
Raspberry Pi ``raspi2`` and ``raspi3`` machines (removed in 6.2)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The Raspberry Pi machines come in various models (A, A+, B, B+). To be able
|
||||
to distinguish which model QEMU is implementing, the ``raspi2`` and ``raspi3``
|
||||
machines have been renamed ``raspi2b`` and ``raspi3b``.
|
||||
|
||||
|
||||
linux-user mode CPUs
|
||||
--------------------
|
||||
|
||||
@@ -260,6 +260,29 @@ clocks get the new clock period value: *Clock 2*, *Clock 3* and *Clock 4*.
|
||||
It is not possible to disconnect a clock or to change the clock connection
|
||||
after it is connected.
|
||||
|
||||
Clock multiplier and divider settings
|
||||
-------------------------------------
|
||||
|
||||
By default, when clocks are connected together, the child
|
||||
clocks run with the same period as their source (parent) clock.
|
||||
The Clock API supports a built-in period multiplier/divider
|
||||
mechanism so you can configure a clock to make its children
|
||||
run at a different period from its own. If you call the
|
||||
``clock_set_mul_div()`` function you can specify the clock's
|
||||
multiplier and divider values. The children of that clock
|
||||
will all run with a period of ``parent_period * multiplier / divider``.
|
||||
For instance, if the clock has a frequency of 8MHz and you set its
|
||||
multiplier to 2 and its divider to 3, the child clocks will run
|
||||
at 12MHz.
|
||||
|
||||
You can change the multiplier and divider of a clock at runtime,
|
||||
so you can use this to model clock controller devices which
|
||||
have guest-programmable frequency multipliers or dividers.
|
||||
|
||||
Note that ``clock_set_mul_div()`` does not automatically call
|
||||
``clock_propagate()``. If you make a runtime change to the
|
||||
multiplier or divider you must call clock_propagate() yourself.
|
||||
|
||||
Unconnected input clocks
|
||||
------------------------
|
||||
|
||||
|
||||
+19
-19
@@ -41,7 +41,7 @@ Nodes
|
||||
|
||||
A node can be of four types:
|
||||
|
||||
- **QNODE_MACHINE**: for example ``arm/raspi2``
|
||||
- **QNODE_MACHINE**: for example ``arm/raspi2b``
|
||||
- **QNODE_DRIVER**: for example ``generic-sdhci``
|
||||
- **QNODE_INTERFACE**: for example ``sdhci`` (interface for all ``-sdhci``
|
||||
drivers).
|
||||
@@ -119,12 +119,12 @@ It is possible to troubleshoot unavailable tests by running::
|
||||
# |-> dest='i440FX-pcihost' type=0 (node=0x5591421117f0)
|
||||
# src=''
|
||||
# |-> dest='x86_64/pc' type=0 (node=0x559142111600)
|
||||
# |-> dest='arm/raspi2' type=0 (node=0x559142110740)
|
||||
# |-> dest='arm/raspi2b' type=0 (node=0x559142110740)
|
||||
...
|
||||
# }
|
||||
# ALL QGRAPH NODES: {
|
||||
# name='virtio-net-tests/announce-self' type=3 cmd_line='(null)' [available]
|
||||
# name='arm/raspi2' type=0 cmd_line='-M raspi2 ' [UNAVAILABLE]
|
||||
# name='arm/raspi2b' type=0 cmd_line='-M raspi2b ' [UNAVAILABLE]
|
||||
...
|
||||
# }
|
||||
|
||||
@@ -135,8 +135,8 @@ qgraph path in the "ALL QGRAPH EDGES" output as follows: '' -> 'x86_64/pc' ->
|
||||
'virtio-net'. The root of the qgraph is '' and the depth first search begins
|
||||
there.
|
||||
|
||||
The ``arm/raspi`` machine node is listed as "UNAVAILABLE". Although it is
|
||||
reachable from the root via '' -> 'arm/raspi2' the node is unavailable because
|
||||
The ``arm/raspi2b`` machine node is listed as "UNAVAILABLE". Although it is
|
||||
reachable from the root via '' -> 'arm/raspi2b' the node is unavailable because
|
||||
the QEMU binary did not list it when queried by the framework. This is expected
|
||||
because we used the ``qemu-system-x86_64`` binary which does not support ARM
|
||||
machine types.
|
||||
@@ -158,7 +158,7 @@ Here we continue the ``sdhci`` use case, with the following scenario:
|
||||
- ``sdhci-test`` aims to test the ``read[q,w], writeq`` functions
|
||||
offered by the ``sdhci`` drivers.
|
||||
- The current ``sdhci`` device is supported by both ``x86_64/pc`` and ``ARM``
|
||||
(in this example we focus on the ``arm-raspi2``) machines.
|
||||
(in this example we focus on the ``arm-raspi2b``) machines.
|
||||
- QEMU offers 2 types of drivers: ``QSDHCI_MemoryMapped`` for ``ARM`` and
|
||||
``QSDHCI_PCI`` for ``x86_64/pc``. Both implement the
|
||||
``read[q,w], writeq`` functions.
|
||||
@@ -180,11 +180,11 @@ In order to implement such scenario in qgraph, the test developer needs to:
|
||||
all the pci drivers available)
|
||||
|
||||
``sdhci-pci --consumes--> pci-bus``
|
||||
- Create an ``arm/raspi2`` machine node. This machine ``contains``
|
||||
- Create an ``arm/raspi2b`` machine node. This machine ``contains``
|
||||
a ``generic-sdhci`` memory mapped ``sdhci`` driver node, representing
|
||||
``QSDHCI_MemoryMapped``.
|
||||
|
||||
``arm/raspi2 --contains--> generic-sdhci``
|
||||
``arm/raspi2b --contains--> generic-sdhci``
|
||||
- Create the ``sdhci`` interface node. This interface offers the
|
||||
functions that are shared by all ``sdhci`` devices.
|
||||
The interface is produced by ``sdhci-pci`` and ``generic-sdhci``,
|
||||
@@ -199,7 +199,7 @@ In order to implement such scenario in qgraph, the test developer needs to:
|
||||
|
||||
``sdhci-test --consumes--> sdhci``
|
||||
|
||||
``arm-raspi2`` machine, simplified from
|
||||
``arm-raspi2b`` machine, simplified from
|
||||
``tests/qtest/libqos/arm-raspi2-machine.c``::
|
||||
|
||||
#include "qgraph.h"
|
||||
@@ -217,7 +217,7 @@ In order to implement such scenario in qgraph, the test developer needs to:
|
||||
return &machine->alloc;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in arm/raspi2\n", interface);
|
||||
fprintf(stderr, "%s not present in arm/raspi2b\n", interface);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ In order to implement such scenario in qgraph, the test developer needs to:
|
||||
return &machine->sdhci.obj;
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s not present in arm/raspi2\n", device);
|
||||
fprintf(stderr, "%s not present in arm/raspi2b\n", device);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
@@ -253,10 +253,10 @@ In order to implement such scenario in qgraph, the test developer needs to:
|
||||
|
||||
static void raspi2_register_nodes(void)
|
||||
{
|
||||
/* arm/raspi2 --contains--> generic-sdhci */
|
||||
qos_node_create_machine("arm/raspi2",
|
||||
/* arm/raspi2b --contains--> generic-sdhci */
|
||||
qos_node_create_machine("arm/raspi2b",
|
||||
qos_create_machine_arm_raspi2);
|
||||
qos_node_contains("arm/raspi2", "generic-sdhci", NULL);
|
||||
qos_node_contains("arm/raspi2b", "generic-sdhci", NULL);
|
||||
}
|
||||
|
||||
libqos_init(raspi2_register_nodes);
|
||||
@@ -470,7 +470,7 @@ In the above example, all possible types of relations are created::
|
||||
|
|
||||
+--produces-- +
|
||||
|
|
||||
arm/raspi2 --contains--> generic-sdhci
|
||||
arm/raspi2b --contains--> generic-sdhci
|
||||
|
||||
or inverting the consumes edge in consumed_by::
|
||||
|
||||
@@ -486,7 +486,7 @@ or inverting the consumes edge in consumed_by::
|
||||
|
|
||||
+--produces-- +
|
||||
|
|
||||
arm/raspi2 --contains--> generic-sdhci
|
||||
arm/raspi2b --contains--> generic-sdhci
|
||||
|
||||
Adding a new test
|
||||
"""""""""""""""""
|
||||
@@ -536,7 +536,7 @@ Final graph will be like this::
|
||||
|
|
||||
+--produces-- +
|
||||
|
|
||||
arm/raspi2 --contains--> generic-sdhci
|
||||
arm/raspi2b --contains--> generic-sdhci
|
||||
|
||||
or inverting the consumes edge in consumed_by::
|
||||
|
||||
@@ -552,7 +552,7 @@ or inverting the consumes edge in consumed_by::
|
||||
|
|
||||
+--produces-- +
|
||||
|
|
||||
arm/raspi2 --contains--> generic-sdhci
|
||||
arm/raspi2b --contains--> generic-sdhci
|
||||
|
||||
Assuming there the binary is
|
||||
``QTEST_QEMU_BINARY=./qemu-system-x86_64``
|
||||
@@ -561,7 +561,7 @@ a valid test path will be:
|
||||
|
||||
and for the binary ``QTEST_QEMU_BINARY=./qemu-system-arm``:
|
||||
|
||||
``/arm/raspi2/generic-sdhci/sdhci/sdhci-test``
|
||||
``/arm/raspi2b/generic-sdhci/sdhci/sdhci-test``
|
||||
|
||||
Additional examples are also in ``test-qgraph.c``
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ Supported guest CPU types:
|
||||
- ``cortex-a53`` (64-bit)
|
||||
- ``cortex-a57`` (64-bit)
|
||||
- ``cortex-a72`` (64-bit)
|
||||
- ``a64fx`` (64-bit)
|
||||
- ``host`` (with KVM only)
|
||||
- ``max`` (same as ``host`` for KVM; best possible emulation with TCG)
|
||||
|
||||
|
||||
@@ -198,7 +198,6 @@ static void parts128_default_nan(FloatParts128 *p, float_status *status)
|
||||
static uint64_t parts_silence_nan_frac(uint64_t frac, float_status *status)
|
||||
{
|
||||
g_assert(!no_signaling_nans(status));
|
||||
g_assert(!status->default_nan_mode);
|
||||
|
||||
/* The only snan_bit_is_one target without default_nan_mode is HPPA. */
|
||||
if (snan_bit_is_one(status)) {
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-16
@@ -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,
|
||||
|
||||
+259
-1
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -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);
|
||||
}
|
||||
|
||||
+46
-22
@@ -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),
|
||||
|
||||
+6
-1
@@ -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);
|
||||
|
||||
|
||||
+6
-6
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
+19
-1
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
+42
-354
@@ -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);
|
||||
}
|
||||
|
||||
+37
-10
@@ -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)) {
|
||||
|
||||
+37
-10
@@ -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)) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user