target-arm queue:
* Implement ID_PFR2 * Conditionalize DBGDIDR * rename xlnx-zcu102.canbusN properties * provide powerdown/reset mechanism for secure firmware on 'virt' board * hw/misc: Fix arith overflow in NPCM7XX PWM module * target/arm: Replace magic value by MMU_DATA_LOAD definition * configure: fix preadv errors on Catalina macOS with new XCode * Various configure and other cleanups in preparation for iOS support * hvf: Add hypervisor entitlement to output binaries (needed for Big Sur) * Implement pvpanic-pci device * Convert the CMSDK timer devices to the Clock framework -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmAUMuIZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3m5ED/9uRVa571OwoyAztgS3HN6e Yi8ddj/isCB/shsJQn9Z6kOqg6WUejvLMyT3d3ulH81eje5s8s8xcGOkch8r7oV+ 2SAi80b92AdXsuIPqLeyx6dgJr8e/6MAzD8gYaAKEJsIbKWJFMb3O1OjyITrGM0N E1F3lLXAut9xxWXgvT+3ES2z+eRxI7gwr6PTDIoCQ5PqQUwqSt8hIn9VCZwaR6l1 3570Yy0ScfDCgAZmk6tUVaPJ3gz8BEE11Iuq2R5N8YtYO9570dZDuvsH0RLplRr2 Wns3ReggjySgB9qmL0ZEl7sLkUDKSS8ud9+75V6h69eUXRqdWUylKgEPjQOs9rFw lhLp0bz+J9KwC1UoQtUXA+/D9M+1xjj1iVhG4CWJe2p4xn5+gzCPz3RLQxLu4ekZ FLAEsph8ftqM9J4a1AsEUf6ghRkG2v/eSKaoBOl5Mq8BOaM+YEZ0T0ZeTQspM9tF iTHk22Ld2aX3aHCbXSnEfND+QEzQXgTQvUHXPTYpYAZPjK4PSfkm6CfsAlir71so TlxwTeoy94dnK4eQjcAHK9GnvRTt5AEImrmC89xAplMYtgBfGmMiFIDysvmCaedt EesNHhh3PAqh7wOiqVa96ALZeAys0LpoBVjzHlmXsfsRgUR+JzxKq3pq0PT1DMcn 92gWwHt3AAqEn4dZ20KxBw== =INlE -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210129-1' into staging target-arm queue: * Implement ID_PFR2 * Conditionalize DBGDIDR * rename xlnx-zcu102.canbusN properties * provide powerdown/reset mechanism for secure firmware on 'virt' board * hw/misc: Fix arith overflow in NPCM7XX PWM module * target/arm: Replace magic value by MMU_DATA_LOAD definition * configure: fix preadv errors on Catalina macOS with new XCode * Various configure and other cleanups in preparation for iOS support * hvf: Add hypervisor entitlement to output binaries (needed for Big Sur) * Implement pvpanic-pci device * Convert the CMSDK timer devices to the Clock framework # gpg: Signature made Fri 29 Jan 2021 16:08:02 GMT # 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-20210129-1: (46 commits) hw/arm/stellaris: Remove board-creation reset of STELLARIS_SYS arm: Remove frq properties on CMSDK timer, dualtimer, watchdog, ARMSSE arm: Don't set freq properties on CMSDK timer, dualtimer, watchdog, ARMSSE hw/arm/armsse: Use Clock to set system_clock_scale tests/qtest/cmsdk-apb-watchdog-test: Test clock changes hw/watchdog/cmsdk-apb-watchdog: Convert to use Clock input hw/timer/cmsdk-apb-dualtimer: Convert to use Clock input hw/timer/cmsdk-apb-timer: Convert to use Clock input hw/arm/stellaris: Create Clock input for watchdog hw/arm/stellaris: Convert SSYS to QOM device hw/arm/musca: Create and connect ARMSSE Clocks hw/arm/mps2-tz: Create and connect ARMSSE Clocks hw/arm/mps2: Create and connect SYSCLK Clock hw/arm/mps2: Inline CMSDK_APB_TIMER creation hw/arm/armsse: Wire up clocks hw/arm/armsse: Rename "MAINCLK" property to "MAINCLK_FRQ" hw/watchdog/cmsdk-apb-watchdog: Add Clock input hw/timer/cmsdk-apb-dualtimer: Add Clock input hw/timer/cmsdk-apb-timer: Add Clock input hw/timer/cmsdk-apb-timer: Rename CMSDKAPBTIMER struct to CMSDKAPBTimer ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9df52f58e7
@ -581,12 +581,15 @@ F: include/hw/rtc/pl031.h
|
||||
F: include/hw/arm/primecell.h
|
||||
F: hw/timer/cmsdk-apb-timer.c
|
||||
F: include/hw/timer/cmsdk-apb-timer.h
|
||||
F: tests/qtest/cmsdk-apb-timer-test.c
|
||||
F: hw/timer/cmsdk-apb-dualtimer.c
|
||||
F: include/hw/timer/cmsdk-apb-dualtimer.h
|
||||
F: tests/qtest/cmsdk-apb-dualtimer-test.c
|
||||
F: hw/char/cmsdk-apb-uart.c
|
||||
F: include/hw/char/cmsdk-apb-uart.h
|
||||
F: hw/watchdog/cmsdk-apb-watchdog.c
|
||||
F: include/hw/watchdog/cmsdk-apb-watchdog.h
|
||||
F: tests/qtest/cmsdk-apb-watchdog-test.c
|
||||
F: hw/misc/tz-ppc.c
|
||||
F: include/hw/misc/tz-ppc.h
|
||||
F: hw/misc/tz-mpc.c
|
||||
|
8
accel/hvf/entitlements.plist
Normal file
8
accel/hvf/entitlements.plist
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.hypervisor</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
78
configure
vendored
78
configure
vendored
@ -238,6 +238,7 @@ cpu=""
|
||||
iasl="iasl"
|
||||
interp_prefix="/usr/gnemul/qemu-%M"
|
||||
static="no"
|
||||
cross_compile="no"
|
||||
cross_prefix=""
|
||||
audio_drv_list=""
|
||||
block_drv_rw_whitelist=""
|
||||
@ -318,6 +319,7 @@ fdt="auto"
|
||||
netmap="no"
|
||||
sdl="auto"
|
||||
sdl_image="auto"
|
||||
coreaudio="auto"
|
||||
virtiofsd="auto"
|
||||
virtfs="auto"
|
||||
libudev="auto"
|
||||
@ -469,6 +471,7 @@ for opt do
|
||||
optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
|
||||
case "$opt" in
|
||||
--cross-prefix=*) cross_prefix="$optarg"
|
||||
cross_compile="yes"
|
||||
;;
|
||||
--cc=*) CC="$optarg"
|
||||
;;
|
||||
@ -622,13 +625,6 @@ fi
|
||||
# the correct CPU with the --cpu option.
|
||||
case $targetos in
|
||||
Darwin)
|
||||
# on Leopard most of the system is 32-bit, so we have to ask the kernel if we can
|
||||
# run 64-bit userspace code.
|
||||
# If the user didn't specify a CPU explicitly and the kernel says this is
|
||||
# 64 bit hw, then assume x86_64. Otherwise fall through to the usual detection code.
|
||||
if test -z "$cpu" && test "$(sysctl -n hw.optional.x86_64)" = "1"; then
|
||||
cpu="x86_64"
|
||||
fi
|
||||
HOST_DSOSUF=".dylib"
|
||||
;;
|
||||
SunOS)
|
||||
@ -772,13 +768,8 @@ OpenBSD)
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
if [ "$cpu" = "x86_64" ] ; then
|
||||
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
|
||||
QEMU_LDFLAGS="-arch x86_64 $QEMU_LDFLAGS"
|
||||
fi
|
||||
audio_drv_list="coreaudio try-sdl"
|
||||
audio_drv_list="try-coreaudio try-sdl"
|
||||
audio_possible_drivers="coreaudio sdl"
|
||||
QEMU_LDFLAGS="-framework CoreFoundation -framework IOKit $QEMU_LDFLAGS"
|
||||
# Disable attempts to use ObjectiveC features in os/object.h since they
|
||||
# won't work when we're compiling with gcc as a C compiler.
|
||||
QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
|
||||
@ -1691,7 +1682,7 @@ $(echo Deprecated targets: $deprecated_targets_list | \
|
||||
--target-list-exclude=LIST exclude a set of targets from the default target-list
|
||||
|
||||
Advanced options (experts only):
|
||||
--cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]
|
||||
--cross-prefix=PREFIX use PREFIX for compile tools, PREFIX can be blank [$cross_prefix]
|
||||
--cc=CC use C compiler CC [$cc]
|
||||
--iasl=IASL use ACPI compiler IASL [$iasl]
|
||||
--host-cc=CC use C compiler CC [$host_cc] for code run at
|
||||
@ -3145,6 +3136,24 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# detect CoreAudio
|
||||
if test "$coreaudio" != "no" ; then
|
||||
coreaudio_libs="-framework CoreAudio"
|
||||
cat > $TMPC << EOF
|
||||
#include <CoreAudio/CoreAudio.h>
|
||||
int main(void)
|
||||
{
|
||||
return (int)AudioGetCurrentHostTime();
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "$coreaudio_libs" ; then
|
||||
coreaudio=yes
|
||||
else
|
||||
coreaudio=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# Sound support libraries probe
|
||||
|
||||
@ -3201,8 +3210,20 @@ for drv in $audio_drv_list; do
|
||||
fi
|
||||
;;
|
||||
|
||||
coreaudio)
|
||||
coreaudio | try-coreaudio)
|
||||
if test "$coreaudio" = "no"; then
|
||||
if test "$drv" = "try-coreaudio"; then
|
||||
audio_drv_list=$(echo "$audio_drv_list" | sed -e 's/try-coreaudio//')
|
||||
else
|
||||
error_exit "$drv check failed" \
|
||||
"Make sure to have the $drv is available."
|
||||
fi
|
||||
else
|
||||
coreaudio_libs="-framework CoreAudio"
|
||||
if test "$drv" = "try-coreaudio"; then
|
||||
audio_drv_list=$(echo "$audio_drv_list" | sed -e 's/try-coreaudio/coreaudio/')
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
|
||||
dsound)
|
||||
@ -3531,19 +3552,6 @@ if compile_prog "" "" ; then
|
||||
iovec=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# preadv probe
|
||||
cat > $TMPC <<EOF
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
int main(void) { return preadv(0, 0, 0, 0); }
|
||||
EOF
|
||||
preadv=no
|
||||
if compile_prog "" "" ; then
|
||||
preadv=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# fdt probe
|
||||
|
||||
@ -5748,9 +5756,6 @@ fi
|
||||
if test "$iovec" = "yes" ; then
|
||||
echo "CONFIG_IOVEC=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$preadv" = "yes" ; then
|
||||
echo "CONFIG_PREADV=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$membarrier" = "yes" ; then
|
||||
echo "CONFIG_MEMBARRIER=y" >> $config_host_mak
|
||||
fi
|
||||
@ -6297,6 +6302,7 @@ echo "cpp_link_args = [${LDFLAGS:+$(meson_quote $LDFLAGS)}]" >> $cross
|
||||
echo "[binaries]" >> $cross
|
||||
echo "c = [$(meson_quote $cc)]" >> $cross
|
||||
test -n "$cxx" && echo "cpp = [$(meson_quote $cxx)]" >> $cross
|
||||
test -n "$objcc" && echo "objc = [$(meson_quote $objcc)]" >> $cross
|
||||
echo "ar = [$(meson_quote $ar)]" >> $cross
|
||||
echo "nm = [$(meson_quote $nm)]" >> $cross
|
||||
echo "pkgconfig = [$(meson_quote $pkg_config_exe)]" >> $cross
|
||||
@ -6306,7 +6312,7 @@ if has $sdl2_config; then
|
||||
fi
|
||||
echo "strip = [$(meson_quote $strip)]" >> $cross
|
||||
echo "windres = [$(meson_quote $windres)]" >> $cross
|
||||
if test -n "$cross_prefix"; then
|
||||
if test "$cross_compile" = "yes"; then
|
||||
cross_arg="--cross-file config-meson.cross"
|
||||
echo "[host_machine]" >> $cross
|
||||
if test "$mingw32" = "yes" ; then
|
||||
@ -6315,10 +6321,16 @@ if test -n "$cross_prefix"; then
|
||||
if test "$linux" = "yes" ; then
|
||||
echo "system = 'linux'" >> $cross
|
||||
fi
|
||||
if test "$darwin" = "yes" ; then
|
||||
echo "system = 'darwin'" >> $cross
|
||||
fi
|
||||
case "$ARCH" in
|
||||
i386|x86_64)
|
||||
i386)
|
||||
echo "cpu_family = 'x86'" >> $cross
|
||||
;;
|
||||
x86_64)
|
||||
echo "cpu_family = 'x86_64'" >> $cross
|
||||
;;
|
||||
ppc64le)
|
||||
echo "cpu_family = 'ppc64'" >> $cross
|
||||
;;
|
||||
|
@ -235,6 +235,22 @@ object during device instance init. For example:
|
||||
/* set initial value to 10ns / 100MHz */
|
||||
clock_set_ns(clk, 10);
|
||||
|
||||
To enforce that the clock is wired up by the board code, you can
|
||||
call ``clock_has_source()`` in your device's realize method:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (!clock_has_source(s->clk)) {
|
||||
error_setg(errp, "MyDevice: clk input must be connected");
|
||||
return;
|
||||
}
|
||||
|
||||
Note that this only checks that the clock has been wired up; it is
|
||||
still possible that the output clock connected to it is disabled
|
||||
or has not yet been configured, in which case the period will be
|
||||
zero. You should use the clock callback to find out when the clock
|
||||
period changes.
|
||||
|
||||
Fetching clock frequency/period
|
||||
-------------------------------
|
||||
|
||||
|
@ -64,6 +64,7 @@ PCI devices (other than virtio):
|
||||
1b36:000d PCI xhci usb host adapter
|
||||
1b36:000f mdpy (mdev sample device), linux/samples/vfio-mdev/mdpy.c
|
||||
1b36:0010 PCIe NVMe device (-device nvme)
|
||||
1b36:0011 PCI PVPanic device (-device pvpanic-pci)
|
||||
|
||||
All these devices are documented in docs/specs.
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
PVPANIC DEVICE
|
||||
==============
|
||||
|
||||
pvpanic device is a simulated ISA device, through which a guest panic
|
||||
pvpanic device is a simulated device, through which a guest panic
|
||||
event is sent to qemu, and a QMP event is generated. This allows
|
||||
management apps (e.g. libvirt) to be notified and respond to the event.
|
||||
|
||||
@ -9,6 +9,9 @@ The management app has the option of waiting for GUEST_PANICKED events,
|
||||
and/or polling for guest-panicked RunState, to learn when the pvpanic
|
||||
device has fired a panic event.
|
||||
|
||||
The pvpanic device can be implemented as an ISA device (using IOPORT) or as a
|
||||
PCI device.
|
||||
|
||||
ISA Interface
|
||||
-------------
|
||||
|
||||
@ -24,6 +27,14 @@ bit 1: a guest panic has happened and will be handled by the guest;
|
||||
the host should record it or report it, but should not affect
|
||||
the execution of the guest.
|
||||
|
||||
PCI Interface
|
||||
-------------
|
||||
|
||||
The PCI interface is similar to the ISA interface except that it uses an MMIO
|
||||
address space provided by its BAR0, 1 byte long. Any machine with a PCI bus
|
||||
can enable a pvpanic device by adding '-device pvpanic-pci' to the command
|
||||
line.
|
||||
|
||||
ACPI Interface
|
||||
--------------
|
||||
|
||||
|
@ -43,6 +43,8 @@ The virt board supports:
|
||||
- Secure-World-only devices if the CPU has TrustZone:
|
||||
|
||||
- A second PL011 UART
|
||||
- A second PL061 GPIO controller, with GPIO lines for triggering
|
||||
a system reset or system poweroff
|
||||
- A secure flash memory
|
||||
- 16MB of secure RAM
|
||||
|
||||
|
@ -17,6 +17,7 @@ config ARM_VIRT
|
||||
select PL011 # UART
|
||||
select PL031 # RTC
|
||||
select PL061 # GPIO
|
||||
select GPIO_PWR
|
||||
select PLATFORM_BUS
|
||||
select SMBIOS
|
||||
select VIRTIO_MMIO
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "hw/arm/armsse.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
|
||||
/* Format of the System Information block SYS_CONFIG register */
|
||||
typedef enum SysConfigFormat {
|
||||
@ -47,7 +48,6 @@ static Property iotkit_properties[] = {
|
||||
DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
|
||||
DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
|
||||
DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
|
||||
DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
|
||||
DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true),
|
||||
@ -59,7 +59,6 @@ static Property armsse_properties[] = {
|
||||
DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION,
|
||||
MemoryRegion *),
|
||||
DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64),
|
||||
DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0),
|
||||
DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15),
|
||||
DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000),
|
||||
DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], false),
|
||||
@ -231,6 +230,16 @@ 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)
|
||||
{
|
||||
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);
|
||||
@ -241,6 +250,10 @@ 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);
|
||||
s->s32kclk = qdev_init_clock_in(DEVICE(s), "S32KCLK", NULL, NULL);
|
||||
|
||||
memory_region_init(&s->container, obj, "armsse-container", UINT64_MAX);
|
||||
|
||||
for (i = 0; i < info->num_cpus; i++) {
|
||||
@ -447,9 +460,11 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->mainclk_frq) {
|
||||
error_setg(errp, "MAINCLK property was not set");
|
||||
return;
|
||||
if (!clock_has_source(s->mainclk)) {
|
||||
error_setg(errp, "MAINCLK clock was not connected");
|
||||
}
|
||||
if (!clock_has_source(s->s32kclk)) {
|
||||
error_setg(errp, "S32KCLK clock was not connected");
|
||||
}
|
||||
|
||||
assert(info->num_cpus <= SSE_MAX_CPUS);
|
||||
@ -710,7 +725,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
* it to the appropriate PPC port; then we can realize the PPC and
|
||||
* map its upstream ends to the right place in the container.
|
||||
*/
|
||||
qdev_prop_set_uint32(DEVICE(&s->timer0), "pclk-frq", s->mainclk_frq);
|
||||
qdev_connect_clock_in(DEVICE(&s->timer0), "pclk", s->mainclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer0), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -720,7 +735,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
object_property_set_link(OBJECT(&s->apb_ppc0), "port[0]", OBJECT(mr),
|
||||
&error_abort);
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->timer1), "pclk-frq", s->mainclk_frq);
|
||||
qdev_connect_clock_in(DEVICE(&s->timer1), "pclk", s->mainclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer1), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -730,7 +745,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
object_property_set_link(OBJECT(&s->apb_ppc0), "port[1]", OBJECT(mr),
|
||||
&error_abort);
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->dualtimer), "pclk-frq", s->mainclk_frq);
|
||||
qdev_connect_clock_in(DEVICE(&s->dualtimer), "TIMCLK", s->mainclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->dualtimer), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -888,7 +903,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
/* Devices behind APB PPC1:
|
||||
* 0x4002f000: S32K timer
|
||||
*/
|
||||
qdev_prop_set_uint32(DEVICE(&s->s32ktimer), "pclk-frq", S32KCLK);
|
||||
qdev_connect_clock_in(DEVICE(&s->s32ktimer), "pclk", s->s32kclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32ktimer), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -981,7 +996,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
qdev_connect_gpio_out(DEVICE(&s->nmi_orgate), 0,
|
||||
qdev_get_gpio_in_named(DEVICE(&s->armv7m), "NMI", 0));
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->s32kwatchdog), "wdogclk-frq", S32KCLK);
|
||||
qdev_connect_clock_in(DEVICE(&s->s32kwatchdog), "WDOGCLK", s->s32kclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->s32kwatchdog), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -991,7 +1006,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
/* 0x40080000 .. 0x4008ffff : ARMSSE second Base peripheral region */
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->nswatchdog), "wdogclk-frq", s->mainclk_frq);
|
||||
qdev_connect_clock_in(DEVICE(&s->nswatchdog), "WDOGCLK", s->mainclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->nswatchdog), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -999,7 +1014,7 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
armsse_get_common_irq_in(s, 1));
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->nswatchdog), 0, 0x40081000);
|
||||
|
||||
qdev_prop_set_uint32(DEVICE(&s->swatchdog), "wdogclk-frq", s->mainclk_frq);
|
||||
qdev_connect_clock_in(DEVICE(&s->swatchdog), "WDOGCLK", s->mainclk);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->swatchdog), errp)) {
|
||||
return;
|
||||
}
|
||||
@ -1104,7 +1119,8 @@ static void armsse_realize(DeviceState *dev, Error **errp)
|
||||
*/
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->container);
|
||||
|
||||
system_clock_scale = NANOSECONDS_PER_SECOND / s->mainclk_frq;
|
||||
/* Set initial system_clock_scale from MAINCLK */
|
||||
armsse_mainclk_update(s);
|
||||
}
|
||||
|
||||
static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
|
||||
@ -1127,9 +1143,11 @@ static void armsse_idau_check(IDAUInterface *ii, uint32_t address,
|
||||
|
||||
static const VMStateDescription armsse_vmstate = {
|
||||
.name = "iotkit",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CLOCK(mainclk, ARMSSE),
|
||||
VMSTATE_CLOCK(s32kclk, ARMSSE),
|
||||
VMSTATE_UINT32(nsccfg, ARMSSE),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include "hw/net/lan9118.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/core/split-irq.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define MPS2TZ_NUMIRQ 92
|
||||
@ -100,6 +101,8 @@ struct MPS2TZMachineState {
|
||||
qemu_or_irq uart_irq_orgate;
|
||||
DeviceState *lan9118;
|
||||
SplitIRQ cpu_irq_splitter[MPS2TZ_NUMIRQ];
|
||||
Clock *sysclk;
|
||||
Clock *s32kclk;
|
||||
};
|
||||
|
||||
#define TYPE_MPS2TZ_MACHINE "mps2tz"
|
||||
@ -110,6 +113,8 @@ OBJECT_DECLARE_TYPE(MPS2TZMachineState, MPS2TZMachineClass, MPS2TZ_MACHINE)
|
||||
|
||||
/* Main SYSCLK frequency in Hz */
|
||||
#define SYSCLK_FRQ 20000000
|
||||
/* Slow 32Khz S32KCLK frequency in Hz */
|
||||
#define S32KCLK_FRQ (32 * 1000)
|
||||
|
||||
/* Create an alias of an entire original MemoryRegion @orig
|
||||
* located at @base in the memory map.
|
||||
@ -396,13 +401,20 @@ static void mps2tz_common_init(MachineState *machine)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* These clocks don't need migration because they are fixed-frequency */
|
||||
mms->sysclk = clock_new(OBJECT(machine), "SYSCLK");
|
||||
clock_set_hz(mms->sysclk, SYSCLK_FRQ);
|
||||
mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK");
|
||||
clock_set_hz(mms->s32kclk, S32KCLK_FRQ);
|
||||
|
||||
object_initialize_child(OBJECT(machine), TYPE_IOTKIT, &mms->iotkit,
|
||||
mmc->armsse_type);
|
||||
iotkitdev = DEVICE(&mms->iotkit);
|
||||
object_property_set_link(OBJECT(&mms->iotkit), "memory",
|
||||
OBJECT(system_memory), &error_abort);
|
||||
qdev_prop_set_uint32(iotkitdev, "EXP_NUMIRQ", MPS2TZ_NUMIRQ);
|
||||
qdev_prop_set_uint32(iotkitdev, "MAINCLK", SYSCLK_FRQ);
|
||||
qdev_connect_clock_in(iotkitdev, "MAINCLK", mms->sysclk);
|
||||
qdev_connect_clock_in(iotkitdev, "S32KCLK", mms->s32kclk);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&mms->iotkit), &error_fatal);
|
||||
|
||||
/*
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "hw/net/lan9118.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/watchdog/cmsdk-apb-watchdog.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
typedef enum MPS2FPGAType {
|
||||
@ -83,6 +84,8 @@ struct MPS2MachineState {
|
||||
/* CMSDK APB subsystem */
|
||||
CMSDKAPBDualTimer dualtimer;
|
||||
CMSDKAPBWatchdog watchdog;
|
||||
CMSDKAPBTimer timer[2];
|
||||
Clock *sysclk;
|
||||
};
|
||||
|
||||
#define TYPE_MPS2_MACHINE "mps2"
|
||||
@ -139,6 +142,10 @@ static void mps2_common_init(MachineState *machine)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* This clock doesn't need migration because it is fixed-frequency */
|
||||
mms->sysclk = clock_new(OBJECT(machine), "SYSCLK");
|
||||
clock_set_hz(mms->sysclk, SYSCLK_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
|
||||
@ -330,18 +337,31 @@ static void mps2_common_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* CMSDK APB subsystem */
|
||||
cmsdk_apb_timer_create(0x40000000, qdev_get_gpio_in(armv7m, 8), SYSCLK_FRQ);
|
||||
cmsdk_apb_timer_create(0x40001000, qdev_get_gpio_in(armv7m, 9), SYSCLK_FRQ);
|
||||
for (i = 0; i < ARRAY_SIZE(mms->timer); i++) {
|
||||
g_autofree char *name = g_strdup_printf("timer%d", i);
|
||||
hwaddr base = 0x40000000 + i * 0x1000;
|
||||
int irqno = 8 + i;
|
||||
SysBusDevice *sbd;
|
||||
|
||||
object_initialize_child(OBJECT(mms), name, &mms->timer[i],
|
||||
TYPE_CMSDK_APB_TIMER);
|
||||
sbd = SYS_BUS_DEVICE(&mms->timer[i]);
|
||||
qdev_connect_clock_in(DEVICE(&mms->timer[i]), "pclk", mms->sysclk);
|
||||
sysbus_realize_and_unref(sbd, &error_fatal);
|
||||
sysbus_mmio_map(sbd, 0, base);
|
||||
sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(armv7m, irqno));
|
||||
}
|
||||
|
||||
object_initialize_child(OBJECT(mms), "dualtimer", &mms->dualtimer,
|
||||
TYPE_CMSDK_APB_DUALTIMER);
|
||||
qdev_prop_set_uint32(DEVICE(&mms->dualtimer), "pclk-frq", SYSCLK_FRQ);
|
||||
qdev_connect_clock_in(DEVICE(&mms->dualtimer), "TIMCLK", mms->sysclk);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&mms->dualtimer), &error_fatal);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&mms->dualtimer), 0,
|
||||
qdev_get_gpio_in(armv7m, 10));
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&mms->dualtimer), 0, 0x40002000);
|
||||
object_initialize_child(OBJECT(mms), "watchdog", &mms->watchdog,
|
||||
TYPE_CMSDK_APB_WATCHDOG);
|
||||
qdev_prop_set_uint32(DEVICE(&mms->watchdog), "wdogclk-frq", SYSCLK_FRQ);
|
||||
qdev_connect_clock_in(DEVICE(&mms->watchdog), "WDOGCLK", mms->sysclk);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&mms->watchdog), &error_fatal);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&mms->watchdog), 0,
|
||||
qdev_get_gpio_in_named(armv7m, "NMI", 0));
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "hw/misc/tz-ppc.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/rtc/pl031.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define MUSCA_NUMIRQ_MAX 96
|
||||
@ -82,6 +83,8 @@ struct MuscaMachineState {
|
||||
UnimplementedDeviceState sdio;
|
||||
UnimplementedDeviceState gpio;
|
||||
UnimplementedDeviceState cryptoisland;
|
||||
Clock *sysclk;
|
||||
Clock *s32kclk;
|
||||
};
|
||||
|
||||
#define TYPE_MUSCA_MACHINE "musca"
|
||||
@ -96,6 +99,8 @@ OBJECT_DECLARE_TYPE(MuscaMachineState, MuscaMachineClass, MUSCA_MACHINE)
|
||||
* don't model that in our SSE-200 model yet.
|
||||
*/
|
||||
#define SYSCLK_FRQ 40000000
|
||||
/* Slow 32Khz S32KCLK frequency in Hz */
|
||||
#define S32KCLK_FRQ (32 * 1000)
|
||||
|
||||
static qemu_irq get_sse_irq_in(MuscaMachineState *mms, int irqno)
|
||||
{
|
||||
@ -367,6 +372,11 @@ static void musca_init(MachineState *machine)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
mms->sysclk = clock_new(OBJECT(machine), "SYSCLK");
|
||||
clock_set_hz(mms->sysclk, SYSCLK_FRQ);
|
||||
mms->s32kclk = clock_new(OBJECT(machine), "S32KCLK");
|
||||
clock_set_hz(mms->s32kclk, S32KCLK_FRQ);
|
||||
|
||||
object_initialize_child(OBJECT(machine), "sse-200", &mms->sse,
|
||||
TYPE_SSE200);
|
||||
ssedev = DEVICE(&mms->sse);
|
||||
@ -375,7 +385,8 @@ static void musca_init(MachineState *machine)
|
||||
qdev_prop_set_uint32(ssedev, "EXP_NUMIRQ", mmc->num_irqs);
|
||||
qdev_prop_set_uint32(ssedev, "init-svtor", mmc->init_svtor);
|
||||
qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width);
|
||||
qdev_prop_set_uint32(ssedev, "MAINCLK", SYSCLK_FRQ);
|
||||
qdev_connect_clock_in(ssedev, "MAINCLK", mms->sysclk);
|
||||
qdev_connect_clock_in(ssedev, "S32KCLK", mms->s32kclk);
|
||||
/*
|
||||
* Musca-A takes the default SSE-200 FPU/DSP settings (ie no for
|
||||
* CPU0 and yes for CPU1); Musca-B1 explicitly enables them for CPU0.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "hw/watchdog/cmsdk-apb-watchdog.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "cpu.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
@ -357,7 +358,12 @@ static void stellaris_gptm_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
/* System controller. */
|
||||
|
||||
typedef struct {
|
||||
#define TYPE_STELLARIS_SYS "stellaris-sys"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ssys_state, STELLARIS_SYS)
|
||||
|
||||
struct ssys_state {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint32_t pborctl;
|
||||
uint32_t ldopctl;
|
||||
@ -371,11 +377,19 @@ typedef struct {
|
||||
uint32_t dcgc[3];
|
||||
uint32_t clkvclr;
|
||||
uint32_t ldoarst;
|
||||
qemu_irq irq;
|
||||
Clock *sysclk;
|
||||
/* Properties (all read-only registers) */
|
||||
uint32_t user0;
|
||||
uint32_t user1;
|
||||
qemu_irq irq;
|
||||
stellaris_board_info *board;
|
||||
} ssys_state;
|
||||
uint32_t did0;
|
||||
uint32_t did1;
|
||||
uint32_t dc0;
|
||||
uint32_t dc1;
|
||||
uint32_t dc2;
|
||||
uint32_t dc3;
|
||||
uint32_t dc4;
|
||||
};
|
||||
|
||||
static void ssys_update(ssys_state *s)
|
||||
{
|
||||
@ -430,7 +444,7 @@ static uint32_t pllcfg_fury[16] = {
|
||||
|
||||
static int ssys_board_class(const ssys_state *s)
|
||||
{
|
||||
uint32_t did0 = s->board->did0;
|
||||
uint32_t did0 = s->did0;
|
||||
switch (did0 & DID0_VER_MASK) {
|
||||
case DID0_VER_0:
|
||||
return DID0_CLASS_SANDSTORM;
|
||||
@ -456,19 +470,19 @@ static uint64_t ssys_read(void *opaque, hwaddr offset,
|
||||
|
||||
switch (offset) {
|
||||
case 0x000: /* DID0 */
|
||||
return s->board->did0;
|
||||
return s->did0;
|
||||
case 0x004: /* DID1 */
|
||||
return s->board->did1;
|
||||
return s->did1;
|
||||
case 0x008: /* DC0 */
|
||||
return s->board->dc0;
|
||||
return s->dc0;
|
||||
case 0x010: /* DC1 */
|
||||
return s->board->dc1;
|
||||
return s->dc1;
|
||||
case 0x014: /* DC2 */
|
||||
return s->board->dc2;
|
||||
return s->dc2;
|
||||
case 0x018: /* DC3 */
|
||||
return s->board->dc3;
|
||||
return s->dc3;
|
||||
case 0x01c: /* DC4 */
|
||||
return s->board->dc4;
|
||||
return s->dc4;
|
||||
case 0x030: /* PBORCTL */
|
||||
return s->pborctl;
|
||||
case 0x034: /* LDOPCTL */
|
||||
@ -543,15 +557,26 @@ static bool ssys_use_rcc2(ssys_state *s)
|
||||
}
|
||||
|
||||
/*
|
||||
* Caculate the sys. clock period in ms.
|
||||
* Calculate the system clock period. We only want to propagate
|
||||
* this change to the rest of the system if we're not being called
|
||||
* from migration post-load.
|
||||
*/
|
||||
static void ssys_calculate_system_clock(ssys_state *s)
|
||||
static void ssys_calculate_system_clock(ssys_state *s, bool propagate_clock)
|
||||
{
|
||||
/*
|
||||
* 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);
|
||||
} else {
|
||||
system_clock_scale = 5 * (((s->rcc >> 23) & 0xf) + 1);
|
||||
}
|
||||
clock_set_ns(s->sysclk, system_clock_scale);
|
||||
if (propagate_clock) {
|
||||
clock_propagate(s->sysclk);
|
||||
}
|
||||
}
|
||||
|
||||
static void ssys_write(void *opaque, hwaddr offset,
|
||||
@ -586,7 +611,7 @@ static void ssys_write(void *opaque, hwaddr offset,
|
||||
s->int_status |= (1 << 6);
|
||||
}
|
||||
s->rcc = value;
|
||||
ssys_calculate_system_clock(s);
|
||||
ssys_calculate_system_clock(s, true);
|
||||
break;
|
||||
case 0x070: /* RCC2 */
|
||||
if (ssys_board_class(s) == DID0_CLASS_SANDSTORM) {
|
||||
@ -598,7 +623,7 @@ static void ssys_write(void *opaque, hwaddr offset,
|
||||
s->int_status |= (1 << 6);
|
||||
}
|
||||
s->rcc2 = value;
|
||||
ssys_calculate_system_clock(s);
|
||||
ssys_calculate_system_clock(s, true);
|
||||
break;
|
||||
case 0x100: /* RCGC0 */
|
||||
s->rcgc[0] = value;
|
||||
@ -646,9 +671,9 @@ static const MemoryRegionOps ssys_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void ssys_reset(void *opaque)
|
||||
static void stellaris_sys_reset_enter(Object *obj, ResetType type)
|
||||
{
|
||||
ssys_state *s = (ssys_state *)opaque;
|
||||
ssys_state *s = STELLARIS_SYS(obj);
|
||||
|
||||
s->pborctl = 0x7ffd;
|
||||
s->rcc = 0x078e3ac0;
|
||||
@ -661,14 +686,25 @@ static void ssys_reset(void *opaque)
|
||||
s->rcgc[0] = 1;
|
||||
s->scgc[0] = 1;
|
||||
s->dcgc[0] = 1;
|
||||
ssys_calculate_system_clock(s);
|
||||
}
|
||||
|
||||
static void stellaris_sys_reset_hold(Object *obj)
|
||||
{
|
||||
ssys_state *s = STELLARIS_SYS(obj);
|
||||
|
||||
/* OK to propagate clocks from the hold phase */
|
||||
ssys_calculate_system_clock(s, true);
|
||||
}
|
||||
|
||||
static void stellaris_sys_reset_exit(Object *obj)
|
||||
{
|
||||
}
|
||||
|
||||
static int stellaris_sys_post_load(void *opaque, int version_id)
|
||||
{
|
||||
ssys_state *s = opaque;
|
||||
|
||||
ssys_calculate_system_clock(s);
|
||||
ssys_calculate_system_clock(s, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -691,30 +727,61 @@ static const VMStateDescription vmstate_stellaris_sys = {
|
||||
VMSTATE_UINT32_ARRAY(dcgc, ssys_state, 3),
|
||||
VMSTATE_UINT32(clkvclr, ssys_state),
|
||||
VMSTATE_UINT32(ldoarst, ssys_state),
|
||||
/* No field for sysclk -- handled in post-load instead */
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static int stellaris_sys_init(uint32_t base, qemu_irq irq,
|
||||
stellaris_board_info * board,
|
||||
uint8_t *macaddr)
|
||||
static Property stellaris_sys_properties[] = {
|
||||
DEFINE_PROP_UINT32("user0", ssys_state, user0, 0),
|
||||
DEFINE_PROP_UINT32("user1", ssys_state, user1, 0),
|
||||
DEFINE_PROP_UINT32("did0", ssys_state, did0, 0),
|
||||
DEFINE_PROP_UINT32("did1", ssys_state, did1, 0),
|
||||
DEFINE_PROP_UINT32("dc0", ssys_state, dc0, 0),
|
||||
DEFINE_PROP_UINT32("dc1", ssys_state, dc1, 0),
|
||||
DEFINE_PROP_UINT32("dc2", ssys_state, dc2, 0),
|
||||
DEFINE_PROP_UINT32("dc3", ssys_state, dc3, 0),
|
||||
DEFINE_PROP_UINT32("dc4", ssys_state, dc4, 0),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
static void stellaris_sys_instance_init(Object *obj)
|
||||
{
|
||||
ssys_state *s;
|
||||
ssys_state *s = STELLARIS_SYS(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(s);
|
||||
|
||||
s = g_new0(ssys_state, 1);
|
||||
s->irq = irq;
|
||||
s->board = board;
|
||||
/* Most devices come preprogrammed with a MAC address in the user data. */
|
||||
s->user0 = macaddr[0] | (macaddr[1] << 8) | (macaddr[2] << 16);
|
||||
s->user1 = macaddr[3] | (macaddr[4] << 8) | (macaddr[5] << 16);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &ssys_ops, s, "ssys", 0x00001000);
|
||||
memory_region_add_subregion(get_system_memory(), base, &s->iomem);
|
||||
ssys_reset(s);
|
||||
vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_stellaris_sys, s);
|
||||
return 0;
|
||||
memory_region_init_io(&s->iomem, obj, &ssys_ops, s, "ssys", 0x00001000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
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. */
|
||||
|
||||
@ -1280,6 +1347,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
|
||||
int flash_size;
|
||||
I2CBus *i2c;
|
||||
DeviceState *dev;
|
||||
DeviceState *ssys_dev;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
@ -1330,16 +1398,15 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
|
||||
}
|
||||
}
|
||||
|
||||
stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
|
||||
board, nd_table[0].macaddr.a);
|
||||
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);
|
||||
|
||||
/* system_clock_scale is valid now */
|
||||
uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale;
|
||||
qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk);
|
||||
qdev_connect_clock_in(dev, "WDOGCLK",
|
||||
qdev_get_clock_out(ssys_dev, "SYSCLK"));
|
||||
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev),
|
||||
@ -1553,11 +1620,32 @@ static const TypeInfo stellaris_adc_info = {
|
||||
.class_init = stellaris_adc_class_init,
|
||||
};
|
||||
|
||||
static void stellaris_sys_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_stellaris_sys;
|
||||
rc->phases.enter = stellaris_sys_reset_enter;
|
||||
rc->phases.hold = stellaris_sys_reset_hold;
|
||||
rc->phases.exit = stellaris_sys_reset_exit;
|
||||
device_class_set_props(dc, stellaris_sys_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo stellaris_sys_info = {
|
||||
.name = TYPE_STELLARIS_SYS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(ssys_state),
|
||||
.instance_init = stellaris_sys_instance_init,
|
||||
.class_init = stellaris_sys_class_init,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
type_init(stellaris_register_types)
|
||||
|
111
hw/arm/virt.c
111
hw/arm/virt.c
@ -153,6 +153,7 @@ static const MemMapEntry base_memmap[] = {
|
||||
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
|
||||
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
|
||||
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
|
||||
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
|
||||
@ -820,17 +821,80 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
static void create_gpio(const VirtMachineState *vms)
|
||||
static void create_gpio_keys(const VirtMachineState *vms,
|
||||
DeviceState *pl061_dev,
|
||||
uint32_t phandle)
|
||||
{
|
||||
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
|
||||
qdev_get_gpio_in(pl061_dev, 3));
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys", "compatible", "gpio-keys");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#size-cells", 0);
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#address-cells", 1);
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys/poweroff");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys/poweroff",
|
||||
"label", "GPIO Key Poweroff");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys/poweroff", "linux,code",
|
||||
KEY_POWER);
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff",
|
||||
"gpios", phandle, 3, 0);
|
||||
}
|
||||
|
||||
#define SECURE_GPIO_POWEROFF 0
|
||||
#define SECURE_GPIO_RESET 1
|
||||
|
||||
static void create_secure_gpio_pwr(const VirtMachineState *vms,
|
||||
DeviceState *pl061_dev,
|
||||
uint32_t phandle)
|
||||
{
|
||||
DeviceState *gpio_pwr_dev;
|
||||
|
||||
/* gpio-pwr */
|
||||
gpio_pwr_dev = sysbus_create_simple("gpio-pwr", -1, NULL);
|
||||
|
||||
/* connect secure pl061 to gpio-pwr */
|
||||
qdev_connect_gpio_out(pl061_dev, SECURE_GPIO_RESET,
|
||||
qdev_get_gpio_in_named(gpio_pwr_dev, "reset", 0));
|
||||
qdev_connect_gpio_out(pl061_dev, SECURE_GPIO_POWEROFF,
|
||||
qdev_get_gpio_in_named(gpio_pwr_dev, "shutdown", 0));
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-poweroff");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "compatible",
|
||||
"gpio-poweroff");
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-poweroff",
|
||||
"gpios", phandle, SECURE_GPIO_POWEROFF, 0);
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "secure-status",
|
||||
"okay");
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-restart");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "compatible",
|
||||
"gpio-restart");
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-restart",
|
||||
"gpios", phandle, SECURE_GPIO_RESET, 0);
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "secure-status",
|
||||
"okay");
|
||||
}
|
||||
|
||||
static void create_gpio_devices(const VirtMachineState *vms, int gpio,
|
||||
MemoryRegion *mem)
|
||||
{
|
||||
char *nodename;
|
||||
DeviceState *pl061_dev;
|
||||
hwaddr base = vms->memmap[VIRT_GPIO].base;
|
||||
hwaddr size = vms->memmap[VIRT_GPIO].size;
|
||||
int irq = vms->irqmap[VIRT_GPIO];
|
||||
hwaddr base = vms->memmap[gpio].base;
|
||||
hwaddr size = vms->memmap[gpio].size;
|
||||
int irq = vms->irqmap[gpio];
|
||||
const char compat[] = "arm,pl061\0arm,primecell";
|
||||
SysBusDevice *s;
|
||||
|
||||
pl061_dev = sysbus_create_simple("pl061", base,
|
||||
qdev_get_gpio_in(vms->gic, irq));
|
||||
pl061_dev = qdev_new("pl061");
|
||||
s = SYS_BUS_DEVICE(pl061_dev);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
|
||||
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
|
||||
|
||||
uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
|
||||
@ -847,21 +911,19 @@ static void create_gpio(const VirtMachineState *vms)
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", phandle);
|
||||
|
||||
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
|
||||
qdev_get_gpio_in(pl061_dev, 3));
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys", "compatible", "gpio-keys");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#size-cells", 0);
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#address-cells", 1);
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys/poweroff");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys/poweroff",
|
||||
"label", "GPIO Key Poweroff");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys/poweroff", "linux,code",
|
||||
KEY_POWER);
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff",
|
||||
"gpios", phandle, 3, 0);
|
||||
if (gpio != VIRT_GPIO) {
|
||||
/* Mark as not usable by the normal world */
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
|
||||
}
|
||||
g_free(nodename);
|
||||
|
||||
/* Child gpio devices */
|
||||
if (gpio == VIRT_GPIO) {
|
||||
create_gpio_keys(vms, pl061_dev, phandle);
|
||||
} else {
|
||||
create_secure_gpio_pwr(vms, pl061_dev, phandle);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_virtio_devices(const VirtMachineState *vms)
|
||||
@ -1990,7 +2052,11 @@ static void machvirt_init(MachineState *machine)
|
||||
if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
|
||||
vms->acpi_dev = create_acpi_ged(vms);
|
||||
} else {
|
||||
create_gpio(vms);
|
||||
create_gpio_devices(vms, VIRT_GPIO, sysmem);
|
||||
}
|
||||
|
||||
if (vms->secure && !vmc->no_secure_gpio) {
|
||||
create_gpio_devices(vms, VIRT_SECURE_GPIO, secure_sysmem);
|
||||
}
|
||||
|
||||
/* connect powerdown request */
|
||||
@ -2608,8 +2674,11 @@ DEFINE_VIRT_MACHINE_AS_LATEST(6, 0)
|
||||
|
||||
static void virt_machine_5_2_options(MachineClass *mc)
|
||||
{
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
|
||||
|
||||
virt_machine_6_0_options(mc);
|
||||
compat_props_add(mc->compat_props, hw_compat_5_2, hw_compat_5_2_len);
|
||||
vmc->no_secure_gpio = true;
|
||||
}
|
||||
DEFINE_VIRT_MACHINE(5, 2)
|
||||
|
||||
|
@ -219,12 +219,12 @@ static void xlnx_zcu102_machine_instance_init(Object *obj)
|
||||
s->secure = false;
|
||||
/* Default to virt (EL2) being disabled */
|
||||
s->virt = false;
|
||||
object_property_add_link(obj, "xlnx-zcu102.canbus0", TYPE_CAN_BUS,
|
||||
object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
|
||||
(Object **)&s->canbus[0],
|
||||
object_property_allow_set_link,
|
||||
0);
|
||||
|
||||
object_property_add_link(obj, "xlnx-zcu102.canbus1", TYPE_CAN_BUS,
|
||||
object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
|
||||
(Object **)&s->canbus[1],
|
||||
object_property_allow_set_link,
|
||||
0);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "sysemu/qtest.h"
|
||||
#include "block/aio.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/clock.h"
|
||||
|
||||
#define DELTA_ADJUST 1
|
||||
#define DELTA_NO_ADJUST -1
|
||||
@ -348,6 +349,39 @@ void ptimer_set_period(ptimer_state *s, int64_t period)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set counter increment interval from a Clock */
|
||||
void ptimer_set_period_from_clock(ptimer_state *s, const Clock *clk,
|
||||
unsigned int divisor)
|
||||
{
|
||||
/*
|
||||
* The raw clock period is a 64-bit value in units of 2^-32 ns;
|
||||
* put another way it's a 32.32 fixed-point ns value. Our internal
|
||||
* representation of the period is 64.32 fixed point ns, so
|
||||
* the conversion is simple.
|
||||
*/
|
||||
uint64_t raw_period = clock_get(clk);
|
||||
uint64_t period_frac;
|
||||
|
||||
assert(s->in_transaction);
|
||||
s->delta = ptimer_get_count(s);
|
||||
s->period = extract64(raw_period, 32, 32);
|
||||
period_frac = extract64(raw_period, 0, 32);
|
||||
/*
|
||||
* divisor specifies a possible frequency divisor between the
|
||||
* clock and the timer, so it is a multiplier on the period.
|
||||
* We do the multiply after splitting the raw period out into
|
||||
* period and frac to avoid having to do a 32*64->96 multiply.
|
||||
*/
|
||||
s->period *= divisor;
|
||||
period_frac *= divisor;
|
||||
s->period += extract64(period_frac, 32, 32);
|
||||
s->period_frac = (uint32_t)period_frac;
|
||||
|
||||
if (s->enabled) {
|
||||
s->need_reload = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set counter frequency in Hz. */
|
||||
void ptimer_set_freq(ptimer_state *s, uint32_t freq)
|
||||
{
|
||||
|
@ -8,5 +8,8 @@ config PL061
|
||||
config GPIO_KEY
|
||||
bool
|
||||
|
||||
config GPIO_PWR
|
||||
bool
|
||||
|
||||
config SIFIVE_GPIO
|
||||
bool
|
||||
|
70
hw/gpio/gpio_pwr.c
Normal file
70
hw/gpio/gpio_pwr.c
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* GPIO qemu power controller
|
||||
*
|
||||
* Copyright (c) 2020 Linaro Limited
|
||||
*
|
||||
* Author: Maxim Uvarov <maxim.uvarov@linaro.org>
|
||||
*
|
||||
* Virtual gpio driver which can be used on top of pl061
|
||||
* to reboot and shutdown qemu virtual machine. One of use
|
||||
* case is gpio driver for secure world application (ARM
|
||||
* Trusted Firmware.).
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
/*
|
||||
* QEMU interface:
|
||||
* two named input GPIO lines:
|
||||
* 'reset' : when asserted, trigger system reset
|
||||
* 'shutdown' : when asserted, trigger system shutdown
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#define TYPE_GPIOPWR "gpio-pwr"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(GPIO_PWR_State, GPIOPWR)
|
||||
|
||||
struct GPIO_PWR_State {
|
||||
SysBusDevice parent_obj;
|
||||
};
|
||||
|
||||
static void gpio_pwr_reset(void *opaque, int n, int level)
|
||||
{
|
||||
if (level) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_pwr_shutdown(void *opaque, int n, int level)
|
||||
{
|
||||
if (level) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
}
|
||||
}
|
||||
|
||||
static void gpio_pwr_init(Object *obj)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
|
||||
qdev_init_gpio_in_named(dev, gpio_pwr_reset, "reset", 1);
|
||||
qdev_init_gpio_in_named(dev, gpio_pwr_shutdown, "shutdown", 1);
|
||||
}
|
||||
|
||||
static const TypeInfo gpio_pwr_info = {
|
||||
.name = TYPE_GPIOPWR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(GPIO_PWR_State),
|
||||
.instance_init = gpio_pwr_init,
|
||||
};
|
||||
|
||||
static void gpio_pwr_register_types(void)
|
||||
{
|
||||
type_register_static(&gpio_pwr_info);
|
||||
}
|
||||
|
||||
type_init(gpio_pwr_register_types)
|
@ -1,5 +1,6 @@
|
||||
softmmu_ss.add(when: 'CONFIG_E500', if_true: files('mpc8xxx.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_gpio.c'))
|
||||
|
@ -14,7 +14,7 @@ config PC
|
||||
imply ISA_DEBUG
|
||||
imply PARALLEL
|
||||
imply PCI_DEVICES
|
||||
imply PVPANIC
|
||||
imply PVPANIC_ISA
|
||||
imply QXL
|
||||
imply SEV
|
||||
imply SGA
|
||||
|
@ -121,9 +121,19 @@ config IOTKIT_SYSCTL
|
||||
config IOTKIT_SYSINFO
|
||||
bool
|
||||
|
||||
config PVPANIC
|
||||
config PVPANIC_COMMON
|
||||
bool
|
||||
|
||||
config PVPANIC_PCI
|
||||
bool
|
||||
default y if PCI_DEVICES
|
||||
depends on PCI
|
||||
select PVPANIC_COMMON
|
||||
|
||||
config PVPANIC_ISA
|
||||
bool
|
||||
depends on ISA_BUS
|
||||
select PVPANIC_COMMON
|
||||
|
||||
config AUX
|
||||
bool
|
||||
|
@ -13,6 +13,7 @@ softmmu_ss.add(when: 'CONFIG_EMC141X', if_true: files('emc141x.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c'))
|
||||
|
||||
# ARM devices
|
||||
softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c'))
|
||||
@ -98,7 +99,8 @@ softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSINFO', if_true: files('iotkit-sysinfo.c')
|
||||
softmmu_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c'))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_PVPANIC', if_true: files('pvpanic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_scu.c', 'aspeed_sdmc.c', 'aspeed_xdma.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c'))
|
||||
|
@ -58,6 +58,9 @@ REG32(NPCM7XX_PWM_PWDR3, 0x50);
|
||||
#define NPCM7XX_CH_INV BIT(2)
|
||||
#define NPCM7XX_CH_MOD BIT(3)
|
||||
|
||||
#define NPCM7XX_MAX_CMR 65535
|
||||
#define NPCM7XX_MAX_CNR 65535
|
||||
|
||||
/* Offset of each PWM channel's prescaler in the PPR register. */
|
||||
static const int npcm7xx_ppr_base[] = { 0, 0, 8, 8 };
|
||||
/* Offset of each PWM channel's clock selector in the CSR register. */
|
||||
@ -96,7 +99,7 @@ static uint32_t npcm7xx_pwm_calculate_freq(NPCM7xxPWM *p)
|
||||
|
||||
static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
|
||||
{
|
||||
uint64_t duty;
|
||||
uint32_t duty;
|
||||
|
||||
if (p->running) {
|
||||
if (p->cnr == 0) {
|
||||
@ -104,7 +107,7 @@ static uint32_t npcm7xx_pwm_calculate_duty(NPCM7xxPWM *p)
|
||||
} else if (p->cmr >= p->cnr) {
|
||||
duty = NPCM7XX_PWM_MAX_DUTY;
|
||||
} else {
|
||||
duty = NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
|
||||
duty = (uint64_t)NPCM7XX_PWM_MAX_DUTY * (p->cmr + 1) / (p->cnr + 1);
|
||||
}
|
||||
} else {
|
||||
duty = 0;
|
||||
@ -357,7 +360,13 @@ static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
|
||||
case A_NPCM7XX_PWM_CNR2:
|
||||
case A_NPCM7XX_PWM_CNR3:
|
||||
p = &s->pwm[npcm7xx_cnr_index(offset)];
|
||||
p->cnr = value;
|
||||
if (value > NPCM7XX_MAX_CNR) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid cnr value: %u", __func__, value);
|
||||
p->cnr = NPCM7XX_MAX_CNR;
|
||||
} else {
|
||||
p->cnr = value;
|
||||
}
|
||||
npcm7xx_pwm_update_output(p);
|
||||
break;
|
||||
|
||||
@ -366,7 +375,13 @@ static void npcm7xx_pwm_write(void *opaque, hwaddr offset,
|
||||
case A_NPCM7XX_PWM_CMR2:
|
||||
case A_NPCM7XX_PWM_CMR3:
|
||||
p = &s->pwm[npcm7xx_cmr_index(offset)];
|
||||
p->cmr = value;
|
||||
if (value > NPCM7XX_MAX_CMR) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid cmr value: %u", __func__, value);
|
||||
p->cmr = NPCM7XX_MAX_CMR;
|
||||
} else {
|
||||
p->cmr = value;
|
||||
}
|
||||
npcm7xx_pwm_update_output(p);
|
||||
break;
|
||||
|
||||
|
94
hw/misc/pvpanic-isa.c
Normal file
94
hw/misc/pvpanic-isa.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* QEMU simulated pvpanic device.
|
||||
*
|
||||
* Copyright Fujitsu, Corp. 2013
|
||||
*
|
||||
* Authors:
|
||||
* Wen Congyang <wency@cn.fujitsu.com>
|
||||
* Hu Tao <hutao@cn.fujitsu.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/misc/pvpanic.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/isa/isa.h"
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicISAState, PVPANIC_ISA_DEVICE)
|
||||
|
||||
/*
|
||||
* PVPanicISAState for ISA device and
|
||||
* use ioport.
|
||||
*/
|
||||
struct PVPanicISAState {
|
||||
ISADevice parent_obj;
|
||||
|
||||
uint16_t ioport;
|
||||
PVPanicState pvpanic;
|
||||
};
|
||||
|
||||
static void pvpanic_isa_initfn(Object *obj)
|
||||
{
|
||||
PVPanicISAState *s = PVPANIC_ISA_DEVICE(obj);
|
||||
|
||||
pvpanic_setup_io(&s->pvpanic, DEVICE(s), 1);
|
||||
}
|
||||
|
||||
static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ISADevice *d = ISA_DEVICE(dev);
|
||||
PVPanicISAState *s = PVPANIC_ISA_DEVICE(dev);
|
||||
PVPanicState *ps = &s->pvpanic;
|
||||
FWCfgState *fw_cfg = fw_cfg_find();
|
||||
uint16_t *pvpanic_port;
|
||||
|
||||
if (!fw_cfg) {
|
||||
return;
|
||||
}
|
||||
|
||||
pvpanic_port = g_malloc(sizeof(*pvpanic_port));
|
||||
*pvpanic_port = cpu_to_le16(s->ioport);
|
||||
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
|
||||
sizeof(*pvpanic_port));
|
||||
|
||||
isa_register_ioport(d, &ps->mr, s->ioport);
|
||||
}
|
||||
|
||||
static Property pvpanic_isa_properties[] = {
|
||||
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicISAState, ioport, 0x505),
|
||||
DEFINE_PROP_UINT8("events", PVPanicISAState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pvpanic_isa_realizefn;
|
||||
device_class_set_props(dc, pvpanic_isa_properties);
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static TypeInfo pvpanic_isa_info = {
|
||||
.name = TYPE_PVPANIC_ISA_DEVICE,
|
||||
.parent = TYPE_ISA_DEVICE,
|
||||
.instance_size = sizeof(PVPanicISAState),
|
||||
.instance_init = pvpanic_isa_initfn,
|
||||
.class_init = pvpanic_isa_class_init,
|
||||
};
|
||||
|
||||
static void pvpanic_register_types(void)
|
||||
{
|
||||
type_register_static(&pvpanic_isa_info);
|
||||
}
|
||||
|
||||
type_init(pvpanic_register_types)
|
94
hw/misc/pvpanic-pci.c
Normal file
94
hw/misc/pvpanic-pci.c
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* QEMU simulated PCI pvpanic device.
|
||||
*
|
||||
* Copyright (C) 2020 Oracle
|
||||
*
|
||||
* Authors:
|
||||
* Mihai Carabas <mihai.carabas@oracle.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/pvpanic.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(PVPanicPCIState, PVPANIC_PCI_DEVICE)
|
||||
|
||||
/*
|
||||
* PVPanicPCIState for PCI device
|
||||
*/
|
||||
typedef struct PVPanicPCIState {
|
||||
PCIDevice dev;
|
||||
PVPanicState pvpanic;
|
||||
} PVPanicPCIState;
|
||||
|
||||
static const VMStateDescription vmstate_pvpanic_pci = {
|
||||
.name = "pvpanic-pci",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, PVPanicPCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void pvpanic_pci_realizefn(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
PVPanicPCIState *s = PVPANIC_PCI_DEVICE(dev);
|
||||
PVPanicState *ps = &s->pvpanic;
|
||||
|
||||
pvpanic_setup_io(&s->pvpanic, DEVICE(s), 2);
|
||||
|
||||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &ps->mr);
|
||||
}
|
||||
|
||||
static Property pvpanic_pci_properties[] = {
|
||||
DEFINE_PROP_UINT8("events", PVPanicPCIState, pvpanic.events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pvpanic_pci_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, pvpanic_pci_properties);
|
||||
|
||||
pc->realize = pvpanic_pci_realizefn;
|
||||
pc->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
pc->device_id = PCI_DEVICE_ID_REDHAT_PVPANIC;
|
||||
pc->revision = 1;
|
||||
pc->class_id = PCI_CLASS_SYSTEM_OTHER;
|
||||
dc->vmsd = &vmstate_pvpanic_pci;
|
||||
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static TypeInfo pvpanic_pci_info = {
|
||||
.name = TYPE_PVPANIC_PCI_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PVPanicPCIState),
|
||||
.class_init = pvpanic_pci_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ }
|
||||
}
|
||||
};
|
||||
|
||||
static void pvpanic_register_types(void)
|
||||
{
|
||||
type_register_static(&pvpanic_pci_info);
|
||||
}
|
||||
|
||||
type_init(pvpanic_register_types);
|
@ -22,18 +22,6 @@
|
||||
#include "hw/misc/pvpanic.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* The bit of supported pv event, TODO: include uapi header and remove this */
|
||||
#define PVPANIC_F_PANICKED 0
|
||||
#define PVPANIC_F_CRASHLOADED 1
|
||||
|
||||
/* The pv event value */
|
||||
#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
|
||||
#define PVPANIC_CRASHLOADED (1 << PVPANIC_F_CRASHLOADED)
|
||||
|
||||
typedef struct PVPanicState PVPanicState;
|
||||
DECLARE_INSTANCE_CHECKER(PVPanicState, ISA_PVPANIC_DEVICE,
|
||||
TYPE_PVPANIC)
|
||||
|
||||
static void handle_event(int event)
|
||||
{
|
||||
static bool logged;
|
||||
@ -54,90 +42,29 @@ static void handle_event(int event)
|
||||
}
|
||||
}
|
||||
|
||||
#include "hw/isa/isa.h"
|
||||
|
||||
struct PVPanicState {
|
||||
ISADevice parent_obj;
|
||||
|
||||
MemoryRegion io;
|
||||
uint16_t ioport;
|
||||
uint8_t events;
|
||||
};
|
||||
|
||||
/* return supported events on read */
|
||||
static uint64_t pvpanic_ioport_read(void *opaque, hwaddr addr, unsigned size)
|
||||
static uint64_t pvpanic_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
PVPanicState *pvp = opaque;
|
||||
return pvp->events;
|
||||
}
|
||||
|
||||
static void pvpanic_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
static void pvpanic_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
handle_event(val);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps pvpanic_ops = {
|
||||
.read = pvpanic_ioport_read,
|
||||
.write = pvpanic_ioport_write,
|
||||
.read = pvpanic_read,
|
||||
.write = pvpanic_write,
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static void pvpanic_isa_initfn(Object *obj)
|
||||
void pvpanic_setup_io(PVPanicState *s, DeviceState *dev, unsigned size)
|
||||
{
|
||||
PVPanicState *s = ISA_PVPANIC_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1);
|
||||
memory_region_init_io(&s->mr, OBJECT(dev), &pvpanic_ops, s, "pvpanic", size);
|
||||
}
|
||||
|
||||
static void pvpanic_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ISADevice *d = ISA_DEVICE(dev);
|
||||
PVPanicState *s = ISA_PVPANIC_DEVICE(dev);
|
||||
FWCfgState *fw_cfg = fw_cfg_find();
|
||||
uint16_t *pvpanic_port;
|
||||
|
||||
if (!fw_cfg) {
|
||||
return;
|
||||
}
|
||||
|
||||
pvpanic_port = g_malloc(sizeof(*pvpanic_port));
|
||||
*pvpanic_port = cpu_to_le16(s->ioport);
|
||||
fw_cfg_add_file(fw_cfg, "etc/pvpanic-port", pvpanic_port,
|
||||
sizeof(*pvpanic_port));
|
||||
|
||||
isa_register_ioport(d, &s->io, s->ioport);
|
||||
}
|
||||
|
||||
static Property pvpanic_isa_properties[] = {
|
||||
DEFINE_PROP_UINT16(PVPANIC_IOPORT_PROP, PVPanicState, ioport, 0x505),
|
||||
DEFINE_PROP_UINT8("events", PVPanicState, events, PVPANIC_PANICKED | PVPANIC_CRASHLOADED),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pvpanic_isa_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = pvpanic_isa_realizefn;
|
||||
device_class_set_props(dc, pvpanic_isa_properties);
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static TypeInfo pvpanic_isa_info = {
|
||||
.name = TYPE_PVPANIC,
|
||||
.parent = TYPE_ISA_DEVICE,
|
||||
.instance_size = sizeof(PVPanicState),
|
||||
.instance_init = pvpanic_isa_initfn,
|
||||
.class_init = pvpanic_isa_class_init,
|
||||
};
|
||||
|
||||
static void pvpanic_register_types(void)
|
||||
{
|
||||
type_register_static(&pvpanic_isa_info);
|
||||
}
|
||||
|
||||
type_init(pvpanic_register_types)
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/timer/cmsdk-apb-dualtimer.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
@ -105,6 +106,22 @@ static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
|
||||
qemu_set_irq(s->timerintc, timintc);
|
||||
}
|
||||
|
||||
static int cmsdk_dualtimermod_divisor(CMSDKAPBDualTimerModule *m)
|
||||
{
|
||||
/* Return the divisor set by the current CONTROL.PRESCALE value */
|
||||
switch (FIELD_EX32(m->control, CONTROL, PRESCALE)) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
return 16;
|
||||
case 2:
|
||||
case 3: /* UNDEFINED, we treat like 2 (and complained when it was set) */
|
||||
return 256;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
|
||||
uint32_t newctrl)
|
||||
{
|
||||
@ -145,7 +162,7 @@ static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
|
||||
ptimer_set_period_from_clock(m->timer, m->parent->timclk, divisor);
|
||||
}
|
||||
|
||||
if (changed & R_CONTROL_MODE_MASK) {
|
||||
@ -413,7 +430,8 @@ static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
|
||||
* limit must both be set to 0xffff, so we wrap at 16 bits.
|
||||
*/
|
||||
ptimer_set_limit(m->timer, 0xffff, 1);
|
||||
ptimer_set_freq(m->timer, m->parent->pclk_frq);
|
||||
ptimer_set_period_from_clock(m->timer, m->parent->timclk,
|
||||
cmsdk_dualtimermod_divisor(m));
|
||||
ptimer_transaction_commit(m->timer);
|
||||
}
|
||||
|
||||
@ -431,6 +449,20 @@ static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
|
||||
s->timeritop = 0;
|
||||
}
|
||||
|
||||
static void cmsdk_apb_dualtimer_clk_update(void *opaque)
|
||||
{
|
||||
CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
|
||||
CMSDKAPBDualTimerModule *m = &s->timermod[i];
|
||||
ptimer_transaction_begin(m->timer);
|
||||
ptimer_set_period_from_clock(m->timer, m->parent->timclk,
|
||||
cmsdk_dualtimermod_divisor(m));
|
||||
ptimer_transaction_commit(m->timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmsdk_apb_dualtimer_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
@ -445,6 +477,8 @@ static void cmsdk_apb_dualtimer_init(Object *obj)
|
||||
for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
|
||||
sysbus_init_irq(sbd, &s->timermod[i].timerint);
|
||||
}
|
||||
s->timclk = qdev_init_clock_in(DEVICE(s), "TIMCLK",
|
||||
cmsdk_apb_dualtimer_clk_update, s);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
|
||||
@ -452,8 +486,8 @@ static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
|
||||
CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
|
||||
int i;
|
||||
|
||||
if (s->pclk_frq == 0) {
|
||||
error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
|
||||
if (!clock_has_source(s->timclk)) {
|
||||
error_setg(errp, "CMSDK APB dualtimer: TIMCLK clock must be connected");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -485,9 +519,10 @@ static const VMStateDescription cmsdk_dualtimermod_vmstate = {
|
||||
|
||||
static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
|
||||
.name = "cmsdk-apb-dualtimer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CLOCK(timclk, CMSDKAPBDualTimer),
|
||||
VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
|
||||
CMSDK_APB_DUALTIMER_NUM_MODULES,
|
||||
1, cmsdk_dualtimermod_vmstate,
|
||||
@ -498,11 +533,6 @@ static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
|
||||
}
|
||||
};
|
||||
|
||||
static Property cmsdk_apb_dualtimer_properties[] = {
|
||||
DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -510,7 +540,6 @@ static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = cmsdk_apb_dualtimer_realize;
|
||||
dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
|
||||
dc->reset = cmsdk_apb_dualtimer_reset;
|
||||
device_class_set_props(dc, cmsdk_apb_dualtimer_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo cmsdk_apb_dualtimer_info = {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/timer/cmsdk-apb-timer.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
@ -67,14 +68,14 @@ static const int timer_id[] = {
|
||||
0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
|
||||
};
|
||||
|
||||
static void cmsdk_apb_timer_update(CMSDKAPBTIMER *s)
|
||||
static void cmsdk_apb_timer_update(CMSDKAPBTimer *s)
|
||||
{
|
||||
qemu_set_irq(s->timerint, !!(s->intstatus & R_INTSTATUS_IRQ_MASK));
|
||||
}
|
||||
|
||||
static uint64_t cmsdk_apb_timer_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(opaque);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
|
||||
uint64_t r;
|
||||
|
||||
switch (offset) {
|
||||
@ -106,7 +107,7 @@ static uint64_t cmsdk_apb_timer_read(void *opaque, hwaddr offset, unsigned size)
|
||||
static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
unsigned size)
|
||||
{
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(opaque);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
|
||||
|
||||
trace_cmsdk_apb_timer_write(offset, value, size);
|
||||
|
||||
@ -181,7 +182,7 @@ static const MemoryRegionOps cmsdk_apb_timer_ops = {
|
||||
|
||||
static void cmsdk_apb_timer_tick(void *opaque)
|
||||
{
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(opaque);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
|
||||
|
||||
if (s->ctrl & R_CTRL_IRQEN_MASK) {
|
||||
s->intstatus |= R_INTSTATUS_IRQ_MASK;
|
||||
@ -191,7 +192,7 @@ static void cmsdk_apb_timer_tick(void *opaque)
|
||||
|
||||
static void cmsdk_apb_timer_reset(DeviceState *dev)
|
||||
{
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(dev);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(dev);
|
||||
|
||||
trace_cmsdk_apb_timer_reset();
|
||||
s->ctrl = 0;
|
||||
@ -203,23 +204,34 @@ static void cmsdk_apb_timer_reset(DeviceState *dev)
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_timer_clk_update(void *opaque)
|
||||
{
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(opaque);
|
||||
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_period_from_clock(s->timer, s->pclk, 1);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_timer_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(obj);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &cmsdk_apb_timer_ops,
|
||||
s, "cmsdk-apb-timer", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->timerint);
|
||||
s->pclk = qdev_init_clock_in(DEVICE(s), "pclk",
|
||||
cmsdk_apb_timer_clk_update, s);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CMSDKAPBTIMER *s = CMSDK_APB_TIMER(dev);
|
||||
CMSDKAPBTimer *s = CMSDK_APB_TIMER(dev);
|
||||
|
||||
if (s->pclk_frq == 0) {
|
||||
error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
|
||||
if (!clock_has_source(s->pclk)) {
|
||||
error_setg(errp, "CMSDK APB timer: pclk clock must be connected");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -230,29 +242,25 @@ static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp)
|
||||
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
|
||||
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_freq(s->timer, s->pclk_frq);
|
||||
ptimer_set_period_from_clock(s->timer, s->pclk, 1);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static const VMStateDescription cmsdk_apb_timer_vmstate = {
|
||||
.name = "cmsdk-apb-timer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(timer, CMSDKAPBTIMER),
|
||||
VMSTATE_UINT32(ctrl, CMSDKAPBTIMER),
|
||||
VMSTATE_UINT32(value, CMSDKAPBTIMER),
|
||||
VMSTATE_UINT32(reload, CMSDKAPBTIMER),
|
||||
VMSTATE_UINT32(intstatus, CMSDKAPBTIMER),
|
||||
VMSTATE_PTIMER(timer, CMSDKAPBTimer),
|
||||
VMSTATE_CLOCK(pclk, CMSDKAPBTimer),
|
||||
VMSTATE_UINT32(ctrl, CMSDKAPBTimer),
|
||||
VMSTATE_UINT32(value, CMSDKAPBTimer),
|
||||
VMSTATE_UINT32(reload, CMSDKAPBTimer),
|
||||
VMSTATE_UINT32(intstatus, CMSDKAPBTimer),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static Property cmsdk_apb_timer_properties[] = {
|
||||
DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBTIMER, pclk_frq, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void cmsdk_apb_timer_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -260,13 +268,12 @@ static void cmsdk_apb_timer_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = cmsdk_apb_timer_realize;
|
||||
dc->vmsd = &cmsdk_apb_timer_vmstate;
|
||||
dc->reset = cmsdk_apb_timer_reset;
|
||||
device_class_set_props(dc, cmsdk_apb_timer_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo cmsdk_apb_timer_info = {
|
||||
.name = TYPE_CMSDK_APB_TIMER,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(CMSDKAPBTIMER),
|
||||
.instance_size = sizeof(CMSDKAPBTimer),
|
||||
.instance_init = cmsdk_apb_timer_init,
|
||||
.class_init = cmsdk_apb_timer_class_init,
|
||||
};
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/watchdog/cmsdk-apb-watchdog.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
@ -309,6 +310,15 @@ static void cmsdk_apb_watchdog_reset(DeviceState *dev)
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_watchdog_clk_update(void *opaque)
|
||||
{
|
||||
CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(opaque);
|
||||
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_period_from_clock(s->timer, s->wdogclk, 1);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static void cmsdk_apb_watchdog_init(Object *obj)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
@ -318,6 +328,8 @@ static void cmsdk_apb_watchdog_init(Object *obj)
|
||||
s, "cmsdk-apb-watchdog", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->wdogint);
|
||||
s->wdogclk = qdev_init_clock_in(DEVICE(s), "WDOGCLK",
|
||||
cmsdk_apb_watchdog_clk_update, s);
|
||||
|
||||
s->is_luminary = false;
|
||||
s->id = cmsdk_apb_watchdog_id;
|
||||
@ -327,9 +339,9 @@ static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(dev);
|
||||
|
||||
if (s->wdogclk_frq == 0) {
|
||||
if (!clock_has_source(s->wdogclk)) {
|
||||
error_setg(errp,
|
||||
"CMSDK APB watchdog: wdogclk-frq property must be set");
|
||||
"CMSDK APB watchdog: WDOGCLK clock must be connected");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -340,15 +352,16 @@ static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
|
||||
PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
|
||||
|
||||
ptimer_transaction_begin(s->timer);
|
||||
ptimer_set_freq(s->timer, s->wdogclk_frq);
|
||||
ptimer_set_period_from_clock(s->timer, s->wdogclk, 1);
|
||||
ptimer_transaction_commit(s->timer);
|
||||
}
|
||||
|
||||
static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
|
||||
.name = "cmsdk-apb-watchdog",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_CLOCK(wdogclk, CMSDKAPBWatchdog),
|
||||
VMSTATE_PTIMER(timer, CMSDKAPBWatchdog),
|
||||
VMSTATE_UINT32(control, CMSDKAPBWatchdog),
|
||||
VMSTATE_UINT32(intstatus, CMSDKAPBWatchdog),
|
||||
@ -360,11 +373,6 @@ static const VMStateDescription cmsdk_apb_watchdog_vmstate = {
|
||||
}
|
||||
};
|
||||
|
||||
static Property cmsdk_apb_watchdog_properties[] = {
|
||||
DEFINE_PROP_UINT32("wdogclk-frq", CMSDKAPBWatchdog, wdogclk_frq, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -372,7 +380,6 @@ static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data)
|
||||
dc->realize = cmsdk_apb_watchdog_realize;
|
||||
dc->vmsd = &cmsdk_apb_watchdog_vmstate;
|
||||
dc->reset = cmsdk_apb_watchdog_reset;
|
||||
device_class_set_props(dc, cmsdk_apb_watchdog_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo cmsdk_apb_watchdog_info = {
|
||||
|
@ -37,9 +37,10 @@
|
||||
* per-CPU identity and control register blocks
|
||||
*
|
||||
* QEMU interface:
|
||||
* + Clock input "MAINCLK": clock for CPUs and most peripherals
|
||||
* + Clock input "S32KCLK": slow 32KHz clock used for a few peripherals
|
||||
* + QOM property "memory" is a MemoryRegion containing the devices provided
|
||||
* by the board model.
|
||||
* + QOM property "MAINCLK" is the frequency of the main system clock
|
||||
* + QOM property "EXP_NUMIRQ" sets the number of expansion interrupts.
|
||||
* (In hardware, the SSE-200 permits the number of expansion interrupts
|
||||
* for the two CPUs to be configured separately, but we restrict it to
|
||||
@ -103,6 +104,7 @@
|
||||
#include "hw/misc/armsse-mhu.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/or-irq.h"
|
||||
#include "hw/clock.h"
|
||||
#include "hw/core/split-irq.h"
|
||||
#include "hw/cpu/cluster.h"
|
||||
#include "qom/object.h"
|
||||
@ -153,9 +155,9 @@ struct ARMSSE {
|
||||
TZPPC apb_ppc0;
|
||||
TZPPC apb_ppc1;
|
||||
TZMPC mpc[IOTS_NUM_MPC];
|
||||
CMSDKAPBTIMER timer0;
|
||||
CMSDKAPBTIMER timer1;
|
||||
CMSDKAPBTIMER s32ktimer;
|
||||
CMSDKAPBTimer timer0;
|
||||
CMSDKAPBTimer timer1;
|
||||
CMSDKAPBTimer s32ktimer;
|
||||
qemu_or_irq ppc_irq_orgate;
|
||||
SplitIRQ sec_resp_splitter;
|
||||
SplitIRQ ppc_irq_splitter[NUM_PPCS];
|
||||
@ -209,10 +211,12 @@ struct ARMSSE {
|
||||
|
||||
uint32_t nsccfg;
|
||||
|
||||
Clock *mainclk;
|
||||
Clock *s32kclk;
|
||||
|
||||
/* Properties */
|
||||
MemoryRegion *board_memory;
|
||||
uint32_t exp_numirq;
|
||||
uint32_t mainclk_frq;
|
||||
uint32_t sram_addr_width;
|
||||
uint32_t init_svtor;
|
||||
bool cpu_fpu[SSE_MAX_CPUS];
|
||||
|
@ -81,6 +81,7 @@ enum {
|
||||
VIRT_GPIO,
|
||||
VIRT_SECURE_UART,
|
||||
VIRT_SECURE_MEM,
|
||||
VIRT_SECURE_GPIO,
|
||||
VIRT_PCDIMM_ACPI,
|
||||
VIRT_ACPI_GED,
|
||||
VIRT_NVDIMM_ACPI,
|
||||
@ -127,6 +128,7 @@ struct VirtMachineClass {
|
||||
bool kvm_no_adjvtime;
|
||||
bool no_kvm_steal_time;
|
||||
bool acpi_expose_flash;
|
||||
bool no_secure_gpio;
|
||||
};
|
||||
|
||||
struct VirtMachineState {
|
||||
|
@ -139,6 +139,21 @@ void clock_clear_callback(Clock *clk);
|
||||
*/
|
||||
void clock_set_source(Clock *clk, Clock *src);
|
||||
|
||||
/**
|
||||
* clock_has_source:
|
||||
* @clk: the clock
|
||||
*
|
||||
* Returns true if the clock has a source clock connected to it.
|
||||
* This is useful for devices which have input clocks which must
|
||||
* be connected by the board/SoC code which creates them. The
|
||||
* device code can use this to check in its realize method that
|
||||
* the clock has been connected.
|
||||
*/
|
||||
static inline bool clock_has_source(const Clock *clk)
|
||||
{
|
||||
return clk->source != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* clock_set:
|
||||
* @clk: the clock to initialize.
|
||||
|
@ -17,13 +17,33 @@
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_PVPANIC "pvpanic"
|
||||
#define TYPE_PVPANIC_ISA_DEVICE "pvpanic"
|
||||
#define TYPE_PVPANIC_PCI_DEVICE "pvpanic-pci"
|
||||
|
||||
#define PVPANIC_IOPORT_PROP "ioport"
|
||||
|
||||
/* The bit of supported pv event, TODO: include uapi header and remove this */
|
||||
#define PVPANIC_F_PANICKED 0
|
||||
#define PVPANIC_F_CRASHLOADED 1
|
||||
|
||||
/* The pv event value */
|
||||
#define PVPANIC_PANICKED (1 << PVPANIC_F_PANICKED)
|
||||
#define PVPANIC_CRASHLOADED (1 << PVPANIC_F_CRASHLOADED)
|
||||
|
||||
/*
|
||||
* PVPanicState for any device type
|
||||
*/
|
||||
typedef struct PVPanicState PVPanicState;
|
||||
struct PVPanicState {
|
||||
MemoryRegion mr;
|
||||
uint8_t events;
|
||||
};
|
||||
|
||||
void pvpanic_setup_io(PVPanicState *s, DeviceState *dev, unsigned size);
|
||||
|
||||
static inline uint16_t pvpanic_port(void)
|
||||
{
|
||||
Object *o = object_resolve_path_type("", TYPE_PVPANIC, NULL);
|
||||
Object *o = object_resolve_path_type("", TYPE_PVPANIC_ISA_DEVICE, NULL);
|
||||
if (!o) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ extern bool pci_available;
|
||||
#define PCI_DEVICE_ID_REDHAT_PCIE_BRIDGE 0x000e
|
||||
#define PCI_DEVICE_ID_REDHAT_MDPY 0x000f
|
||||
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010
|
||||
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
|
||||
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100
|
||||
|
||||
#define FMT_PCIBUS PRIx64
|
||||
|
@ -165,6 +165,28 @@ void ptimer_transaction_commit(ptimer_state *s);
|
||||
*/
|
||||
void ptimer_set_period(ptimer_state *s, int64_t period);
|
||||
|
||||
/**
|
||||
* ptimer_set_period_from_clock - Set counter increment from a Clock
|
||||
* @s: ptimer to configure
|
||||
* @clk: pointer to Clock object to take period from
|
||||
* @divisor: value to scale the clock frequency down by
|
||||
*
|
||||
* If the ptimer is being driven from a Clock, this is the preferred
|
||||
* way to tell the ptimer about the period, because it avoids any
|
||||
* possible rounding errors that might happen if the internal
|
||||
* representation of the Clock period was converted to either a period
|
||||
* in ns or a frequency in Hz.
|
||||
*
|
||||
* If the ptimer should run at the same frequency as the clock,
|
||||
* pass 1 as the @divisor; if the ptimer should run at half the
|
||||
* frequency, pass 2, and so on.
|
||||
*
|
||||
* This function will assert if it is called outside a
|
||||
* ptimer_transaction_begin/commit block.
|
||||
*/
|
||||
void ptimer_set_period_from_clock(ptimer_state *s, const Clock *clock,
|
||||
unsigned int divisor);
|
||||
|
||||
/**
|
||||
* ptimer_set_freq - Set counter frequency in Hz
|
||||
* @s: ptimer to configure
|
||||
|
@ -16,7 +16,7 @@
|
||||
* https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
|
||||
*
|
||||
* QEMU interface:
|
||||
* + QOM property "pclk-frq": frequency at which the timer is clocked
|
||||
* + Clock input "TIMCLK": clock (for both timers)
|
||||
* + sysbus MMIO region 0: the register bank
|
||||
* + sysbus IRQ 0: combined timer interrupt TIMINTC
|
||||
* + sysbus IRO 1: timer block 1 interrupt TIMINT1
|
||||
@ -28,6 +28,7 @@
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "hw/clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_CMSDK_APB_DUALTIMER "cmsdk-apb-dualtimer"
|
||||
@ -61,7 +62,7 @@ struct CMSDKAPBDualTimer {
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
qemu_irq timerintc;
|
||||
uint32_t pclk_frq;
|
||||
Clock *timclk;
|
||||
|
||||
CMSDKAPBDualTimerModule timermod[CMSDK_APB_DUALTIMER_NUM_MODULES];
|
||||
uint32_t timeritcr;
|
||||
|
@ -15,20 +15,27 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "hw/clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_CMSDK_APB_TIMER "cmsdk-apb-timer"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(CMSDKAPBTIMER, CMSDK_APB_TIMER)
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(CMSDKAPBTimer, CMSDK_APB_TIMER)
|
||||
|
||||
struct CMSDKAPBTIMER {
|
||||
/*
|
||||
* QEMU interface:
|
||||
* + Clock input "pclk": clock for the timer
|
||||
* + sysbus MMIO region 0: the register bank
|
||||
* + sysbus IRQ 0: timer interrupt TIMERINT
|
||||
*/
|
||||
struct CMSDKAPBTimer {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
qemu_irq timerint;
|
||||
uint32_t pclk_frq;
|
||||
struct ptimer_state *timer;
|
||||
Clock *pclk;
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t value;
|
||||
@ -36,25 +43,4 @@ struct CMSDKAPBTIMER {
|
||||
uint32_t intstatus;
|
||||
};
|
||||
|
||||
/**
|
||||
* cmsdk_apb_timer_create - convenience function to create TYPE_CMSDK_APB_TIMER
|
||||
* @addr: location in system memory to map registers
|
||||
* @pclk_frq: frequency in Hz of the PCLK clock (used for calculating baud rate)
|
||||
*/
|
||||
static inline DeviceState *cmsdk_apb_timer_create(hwaddr addr,
|
||||
qemu_irq timerint,
|
||||
uint32_t pclk_frq)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusDevice *s;
|
||||
|
||||
dev = qdev_new(TYPE_CMSDK_APB_TIMER);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
qdev_prop_set_uint32(dev, "pclk-frq", pclk_frq);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, addr);
|
||||
sysbus_connect_irq(s, 0, timerint);
|
||||
return dev;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -16,7 +16,7 @@
|
||||
* https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
|
||||
*
|
||||
* QEMU interface:
|
||||
* + QOM property "wdogclk-frq": frequency at which the watchdog is clocked
|
||||
* + Clock input "WDOGCLK": clock for the watchdog's timer
|
||||
* + sysbus MMIO region 0: the register bank
|
||||
* + sysbus IRQ 0: watchdog interrupt
|
||||
*
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "hw/clock.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_CMSDK_APB_WATCHDOG "cmsdk-apb-watchdog"
|
||||
@ -51,9 +52,9 @@ struct CMSDKAPBWatchdog {
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
qemu_irq wdogint;
|
||||
uint32_t wdogclk_frq;
|
||||
bool is_luminary;
|
||||
struct ptimer_state *timer;
|
||||
Clock *wdogclk;
|
||||
|
||||
uint32_t control;
|
||||
uint32_t intstatus;
|
||||
|
@ -710,4 +710,16 @@ static inline void qemu_thread_jit_write(void) {}
|
||||
static inline void qemu_thread_jit_execute(void) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Platforms which do not support system() return ENOSYS
|
||||
*/
|
||||
#ifndef HAVE_SYSTEM_FUNCTION
|
||||
#define system platform_does_not_support_system
|
||||
static inline int platform_does_not_support_system(const char *command)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif /* !HAVE_SYSTEM_FUNCTION */
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@ typedef struct BlockDriverState BlockDriverState;
|
||||
typedef struct BusClass BusClass;
|
||||
typedef struct BusState BusState;
|
||||
typedef struct Chardev Chardev;
|
||||
typedef struct Clock Clock;
|
||||
typedef struct CompatProperty CompatProperty;
|
||||
typedef struct CoMutex CoMutex;
|
||||
typedef struct CPUAddressSpace CPUAddressSpace;
|
||||
|
34
meson.build
34
meson.build
@ -1127,6 +1127,9 @@ config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h'))
|
||||
config_host_data.set('HAVE_PTY_H', cc.has_header('pty.h'))
|
||||
config_host_data.set('HAVE_SYS_IOCCOM_H', cc.has_header('sys/ioccom.h'))
|
||||
config_host_data.set('HAVE_SYS_KCOV_H', cc.has_header('sys/kcov.h'))
|
||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||
|
||||
config_host_data.set('CONFIG_PREADV', cc.has_function('preadv', prefix: '#include <sys/uio.h>'))
|
||||
|
||||
ignored = ['CONFIG_QEMU_INTERP_PREFIX'] # actually per-target
|
||||
arrays = ['CONFIG_AUDIO_DRIVERS', 'CONFIG_BDRV_RW_WHITELIST', 'CONFIG_BDRV_RO_WHITELIST']
|
||||
@ -2164,9 +2167,14 @@ foreach target : target_dirs
|
||||
}]
|
||||
endif
|
||||
foreach exe: execs
|
||||
emulators += {exe['name']:
|
||||
executable(exe['name'], exe['sources'],
|
||||
install: true,
|
||||
exe_name = exe['name']
|
||||
exe_sign = 'CONFIG_HVF' in config_target
|
||||
if exe_sign
|
||||
exe_name += '-unsigned'
|
||||
endif
|
||||
|
||||
emulator = executable(exe_name, exe['sources'],
|
||||
install: not exe_sign,
|
||||
c_args: c_args,
|
||||
dependencies: arch_deps + deps + exe['dependencies'],
|
||||
objects: lib.extract_all_objects(recursive: true),
|
||||
@ -2174,7 +2182,23 @@ foreach target : target_dirs
|
||||
link_depends: [block_syms, qemu_syms] + exe.get('link_depends', []),
|
||||
link_args: link_args,
|
||||
gui_app: exe['gui'])
|
||||
}
|
||||
|
||||
if exe_sign
|
||||
emulators += {exe['name'] : custom_target(exe['name'],
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
depends: emulator,
|
||||
output: exe['name'],
|
||||
command: [
|
||||
meson.current_source_dir() / 'scripts/entitlement.sh',
|
||||
meson.current_build_dir() / exe_name,
|
||||
meson.current_build_dir() / exe['name'],
|
||||
meson.current_source_dir() / 'accel/hvf/entitlements.plist'
|
||||
])
|
||||
}
|
||||
else
|
||||
emulators += {exe['name']: emulator}
|
||||
endif
|
||||
|
||||
if 'CONFIG_TRACE_SYSTEMTAP' in config_host
|
||||
foreach stp: [
|
||||
@ -2414,7 +2438,7 @@ summary_info += {'PIE': get_option('b_pie')}
|
||||
summary_info += {'static build': config_host.has_key('CONFIG_STATIC')}
|
||||
summary_info += {'malloc trim support': has_malloc_trim}
|
||||
summary_info += {'membarrier': config_host.has_key('CONFIG_MEMBARRIER')}
|
||||
summary_info += {'preadv support': config_host.has_key('CONFIG_PREADV')}
|
||||
summary_info += {'preadv support': config_host_data.get('CONFIG_PREADV')}
|
||||
summary_info += {'fdatasync': config_host.has_key('CONFIG_FDATASYNC')}
|
||||
summary_info += {'madvise': config_host.has_key('CONFIG_MADVISE')}
|
||||
summary_info += {'posix_madvise': config_host.has_key('CONFIG_POSIX_MADVISE')}
|
||||
|
13
scripts/entitlement.sh
Executable file
13
scripts/entitlement.sh
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# Helper script for the build process to apply entitlements
|
||||
|
||||
SRC="$1"
|
||||
DST="$2"
|
||||
ENTITLEMENT="$3"
|
||||
|
||||
trap 'rm "$DST.tmp"' exit
|
||||
cp -af "$SRC" "$DST.tmp"
|
||||
codesign --entitlements "$ENTITLEMENT" --force -s - "$DST.tmp"
|
||||
mv "$DST.tmp" "$DST"
|
||||
trap '' exit
|
@ -922,6 +922,7 @@ struct ARMCPU {
|
||||
uint32_t id_mmfr4;
|
||||
uint32_t id_pfr0;
|
||||
uint32_t id_pfr1;
|
||||
uint32_t id_pfr2;
|
||||
uint32_t mvfr0;
|
||||
uint32_t mvfr1;
|
||||
uint32_t mvfr2;
|
||||
|
@ -6567,11 +6567,21 @@ static void define_debug_regs(ARMCPU *cpu)
|
||||
*/
|
||||
int i;
|
||||
int wrps, brps, ctx_cmps;
|
||||
ARMCPRegInfo dbgdidr = {
|
||||
.name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL0_R, .accessfn = access_tda,
|
||||
.type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr,
|
||||
};
|
||||
|
||||
/*
|
||||
* The Arm ARM says DBGDIDR is optional and deprecated if EL1 cannot
|
||||
* use AArch32. Given that bit 15 is RES1, if the value is 0 then
|
||||
* the register must not exist for this cpu.
|
||||
*/
|
||||
if (cpu->isar.dbgdidr != 0) {
|
||||
ARMCPRegInfo dbgdidr = {
|
||||
.name = "DBGDIDR", .cp = 14, .crn = 0, .crm = 0,
|
||||
.opc1 = 0, .opc2 = 0,
|
||||
.access = PL0_R, .accessfn = access_tda,
|
||||
.type = ARM_CP_CONST, .resetvalue = cpu->isar.dbgdidr,
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &dbgdidr);
|
||||
}
|
||||
|
||||
/* Note that all these register fields hold "number of Xs minus 1". */
|
||||
brps = arm_num_brps(cpu);
|
||||
@ -6580,7 +6590,6 @@ static void define_debug_regs(ARMCPU *cpu)
|
||||
|
||||
assert(ctx_cmps <= brps);
|
||||
|
||||
define_one_arm_cp_reg(cpu, &dbgdidr);
|
||||
define_arm_cp_regs(cpu, debug_cp_reginfo);
|
||||
|
||||
if (arm_feature(&cpu->env, ARM_FEATURE_LPAE)) {
|
||||
@ -7662,11 +7671,11 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.accessfn = access_aa64_tid3,
|
||||
.resetvalue = 0 },
|
||||
{ .name = "MVFR4_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
{ .name = "ID_PFR2", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 4,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
.accessfn = access_aa64_tid3,
|
||||
.resetvalue = 0 },
|
||||
.resetvalue = cpu->isar.id_pfr2 },
|
||||
{ .name = "MVFR5_EL1_RESERVED", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 3, .opc2 = 5,
|
||||
.access = PL1_R, .type = ARM_CP_CONST,
|
||||
@ -12409,7 +12418,7 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
|
||||
|
||||
*attrs = (MemTxAttrs) {};
|
||||
|
||||
ret = get_phys_addr(env, addr, 0, mmu_idx, &phys_addr,
|
||||
ret = get_phys_addr(env, addr, MMU_DATA_LOAD, mmu_idx, &phys_addr,
|
||||
attrs, &prot, &page_size, &fi, &cacheattrs);
|
||||
|
||||
if (ret) {
|
||||
|
@ -578,6 +578,8 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
||||
ARM64_SYS_REG(3, 0, 0, 1, 0));
|
||||
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr1,
|
||||
ARM64_SYS_REG(3, 0, 0, 1, 1));
|
||||
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_pfr2,
|
||||
ARM64_SYS_REG(3, 0, 0, 3, 4));
|
||||
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_dfr0,
|
||||
ARM64_SYS_REG(3, 0, 0, 1, 2));
|
||||
err |= read_sys_reg32(fdarray[2], &ahcf->isar.id_mmfr0,
|
||||
|
130
tests/qtest/cmsdk-apb-dualtimer-test.c
Normal file
130
tests/qtest/cmsdk-apb-dualtimer-test.c
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* QTest testcase for the CMSDK APB dualtimer device
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest-single.h"
|
||||
|
||||
/* IoTKit/ARMSSE dualtimer; driven at 25MHz in mps2-an385, so 40ns per tick */
|
||||
#define TIMER_BASE 0x40002000
|
||||
|
||||
#define TIMER1LOAD 0
|
||||
#define TIMER1VALUE 4
|
||||
#define TIMER1CONTROL 8
|
||||
#define TIMER1INTCLR 0xc
|
||||
#define TIMER1RIS 0x10
|
||||
#define TIMER1MIS 0x14
|
||||
#define TIMER1BGLOAD 0x18
|
||||
|
||||
#define TIMER2LOAD 0x20
|
||||
#define TIMER2VALUE 0x24
|
||||
#define TIMER2CONTROL 0x28
|
||||
#define TIMER2INTCLR 0x2c
|
||||
#define TIMER2RIS 0x30
|
||||
#define TIMER2MIS 0x34
|
||||
#define TIMER2BGLOAD 0x38
|
||||
|
||||
#define CTRL_ENABLE (1 << 7)
|
||||
#define CTRL_PERIODIC (1 << 6)
|
||||
#define CTRL_INTEN (1 << 5)
|
||||
#define CTRL_PRESCALE_1 (0 << 2)
|
||||
#define CTRL_PRESCALE_16 (1 << 2)
|
||||
#define CTRL_PRESCALE_256 (2 << 2)
|
||||
#define CTRL_32BIT (1 << 1)
|
||||
#define CTRL_ONESHOT (1 << 0)
|
||||
|
||||
static void test_dualtimer(void)
|
||||
{
|
||||
g_assert_true(readl(TIMER_BASE + TIMER1RIS) == 0);
|
||||
|
||||
/* Start timer: will fire after 40000 ns */
|
||||
writel(TIMER_BASE + TIMER1LOAD, 1000);
|
||||
/* enable in free-running, wrapping, interrupt mode */
|
||||
writel(TIMER_BASE + TIMER1CONTROL, CTRL_ENABLE | CTRL_INTEN);
|
||||
|
||||
/* Step to just past the 500th tick and check VALUE */
|
||||
clock_step(500 * 40 + 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1RIS), ==, 0);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1VALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(500 * 40);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1RIS), ==, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1VALUE), ==, 0);
|
||||
|
||||
/*
|
||||
* We are in free-running wrapping 16-bit mode, so on the following
|
||||
* tick VALUE should have wrapped round to 0xffff.
|
||||
*/
|
||||
clock_step(40);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1VALUE), ==, 0xffff);
|
||||
|
||||
/* Check that any write to INTCLR clears interrupt */
|
||||
writel(TIMER_BASE + TIMER1INTCLR, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER1RIS), ==, 0);
|
||||
|
||||
/* Turn off the timer */
|
||||
writel(TIMER_BASE + TIMER1CONTROL, 0);
|
||||
}
|
||||
|
||||
static void test_prescale(void)
|
||||
{
|
||||
g_assert_true(readl(TIMER_BASE + TIMER2RIS) == 0);
|
||||
|
||||
/* Start timer: will fire after 40 * 256 * 1000 == 1024000 ns */
|
||||
writel(TIMER_BASE + TIMER2LOAD, 1000);
|
||||
/* enable in periodic, wrapping, interrupt mode, prescale 256 */
|
||||
writel(TIMER_BASE + TIMER2CONTROL,
|
||||
CTRL_ENABLE | CTRL_INTEN | CTRL_PERIODIC | CTRL_PRESCALE_256);
|
||||
|
||||
/* Step to just past the 500th tick and check VALUE */
|
||||
clock_step(40 * 256 * 501);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2RIS), ==, 0);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2VALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(40 * 256 * 500);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2RIS), ==, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2VALUE), ==, 0);
|
||||
|
||||
/* In periodic mode the tick VALUE now reloads */
|
||||
clock_step(40 * 256);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2VALUE), ==, 1000);
|
||||
|
||||
/* Check that any write to INTCLR clears interrupt */
|
||||
writel(TIMER_BASE + TIMER2INTCLR, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + TIMER2RIS), ==, 0);
|
||||
|
||||
/* Turn off the timer */
|
||||
writel(TIMER_BASE + TIMER2CONTROL, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_start("-machine mps2-an385");
|
||||
|
||||
qtest_add_func("/cmsdk-apb-dualtimer/dualtimer", test_dualtimer);
|
||||
qtest_add_func("/cmsdk-apb-dualtimer/prescale", test_prescale);
|
||||
|
||||
r = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return r;
|
||||
}
|
75
tests/qtest/cmsdk-apb-timer-test.c
Normal file
75
tests/qtest/cmsdk-apb-timer-test.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* QTest testcase for the CMSDK APB timer device
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest-single.h"
|
||||
|
||||
/* IoTKit/ARMSSE-200 timer0; driven at 25MHz in mps2-an385, so 40ns per tick */
|
||||
#define TIMER_BASE 0x40000000
|
||||
|
||||
#define CTRL 0
|
||||
#define VALUE 4
|
||||
#define RELOAD 8
|
||||
#define INTSTATUS 0xc
|
||||
|
||||
static void test_timer(void)
|
||||
{
|
||||
g_assert_true(readl(TIMER_BASE + INTSTATUS) == 0);
|
||||
|
||||
/* Start timer: will fire after 40 * 1000 == 40000 ns */
|
||||
writel(TIMER_BASE + RELOAD, 1000);
|
||||
writel(TIMER_BASE + CTRL, 9);
|
||||
|
||||
/* Step to just past the 500th tick and check VALUE */
|
||||
clock_step(40 * 500 + 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + INTSTATUS), ==, 0);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + VALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(40 * 500);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + INTSTATUS), ==, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + VALUE), ==, 0);
|
||||
|
||||
/* VALUE reloads at the following tick */
|
||||
clock_step(40);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + VALUE), ==, 1000);
|
||||
|
||||
/* Check write-1-to-clear behaviour of INTSTATUS */
|
||||
writel(TIMER_BASE + INTSTATUS, 0);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + INTSTATUS), ==, 1);
|
||||
writel(TIMER_BASE + INTSTATUS, 1);
|
||||
g_assert_cmpuint(readl(TIMER_BASE + INTSTATUS), ==, 0);
|
||||
|
||||
/* Turn off the timer */
|
||||
writel(TIMER_BASE + CTRL, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_start("-machine mps2-an385");
|
||||
|
||||
qtest_add_func("/cmsdk-apb-timer/timer", test_timer);
|
||||
|
||||
r = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return r;
|
||||
}
|
131
tests/qtest/cmsdk-apb-watchdog-test.c
Normal file
131
tests/qtest/cmsdk-apb-watchdog-test.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* QTest testcase for the CMSDK APB watchdog device
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "libqtest-single.h"
|
||||
|
||||
/*
|
||||
* lm3s811evb watchdog; at board startup this runs at 200MHz / 16 == 12.5MHz,
|
||||
* which is 80ns per tick.
|
||||
*/
|
||||
#define WDOG_BASE 0x40000000
|
||||
|
||||
#define WDOGLOAD 0
|
||||
#define WDOGVALUE 4
|
||||
#define WDOGCONTROL 8
|
||||
#define WDOGINTCLR 0xc
|
||||
#define WDOGRIS 0x10
|
||||
#define WDOGMIS 0x14
|
||||
#define WDOGLOCK 0xc00
|
||||
|
||||
#define SSYS_BASE 0x400fe000
|
||||
#define RCC 0x60
|
||||
#define SYSDIV_SHIFT 23
|
||||
#define SYSDIV_LENGTH 4
|
||||
|
||||
static void test_watchdog(void)
|
||||
{
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
|
||||
writel(WDOG_BASE + WDOGCONTROL, 1);
|
||||
writel(WDOG_BASE + WDOGLOAD, 1000);
|
||||
|
||||
/* Step to just past the 500th tick */
|
||||
clock_step(500 * 80 + 1);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(500 * 80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
|
||||
|
||||
/* VALUE reloads at following tick */
|
||||
clock_step(80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
|
||||
/* Writing any value to WDOGINTCLR clears the interrupt and reloads */
|
||||
clock_step(500 * 80);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
writel(WDOG_BASE + WDOGINTCLR, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
}
|
||||
|
||||
static void test_clock_change(void)
|
||||
{
|
||||
uint32_t rcc;
|
||||
|
||||
/*
|
||||
* Test that writing to the stellaris board's RCC register to
|
||||
* change the system clock frequency causes the watchdog
|
||||
* to change the speed it counts at.
|
||||
*/
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
|
||||
writel(WDOG_BASE + WDOGCONTROL, 1);
|
||||
writel(WDOG_BASE + WDOGLOAD, 1000);
|
||||
|
||||
/* Step to just past the 500th tick */
|
||||
clock_step(80 * 500 + 1);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
|
||||
/* Rewrite RCC.SYSDIV from 16 to 8, so the clock is now 40ns per tick */
|
||||
rcc = readl(SSYS_BASE + RCC);
|
||||
g_assert_cmpuint(extract32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH), ==, 0xf);
|
||||
rcc = deposit32(rcc, SYSDIV_SHIFT, SYSDIV_LENGTH, 7);
|
||||
writel(SSYS_BASE + RCC, rcc);
|
||||
|
||||
/* Just past the 1000th tick: timer should have fired */
|
||||
clock_step(40 * 500);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 0);
|
||||
|
||||
/* VALUE reloads at following tick */
|
||||
clock_step(41);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
|
||||
/* Writing any value to WDOGINTCLR clears the interrupt and reloads */
|
||||
clock_step(40 * 500);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 500);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 1);
|
||||
writel(WDOG_BASE + WDOGINTCLR, 0);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGVALUE), ==, 1000);
|
||||
g_assert_cmpuint(readl(WDOG_BASE + WDOGRIS), ==, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int r;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_start("-machine lm3s811evb");
|
||||
|
||||
qtest_add_func("/cmsdk-apb-watchdog/watchdog", test_watchdog);
|
||||
qtest_add_func("/cmsdk-apb-watchdog/watchdog_clock_change",
|
||||
test_clock_change);
|
||||
|
||||
r = g_test_run();
|
||||
|
||||
qtest_end();
|
||||
|
||||
return r;
|
||||
}
|
@ -33,7 +33,8 @@ qtests_i386 = \
|
||||
(config_host.has_key('CONFIG_LINUX') and \
|
||||
config_all_devices.has_key('CONFIG_ISA_IPMI_BT') ? ['ipmi-bt-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_WDT_IB700') ? ['wdt_ib700-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PVPANIC') ? ['pvpanic-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PVPANIC_ISA') ? ['pvpanic-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PVPANIC_PCI') ? ['pvpanic-pci-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_HDA') ? ['intel-hda-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_I82801B11') ? ['i82801b11-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_IOH3420') ? ['ioh3420-test'] : []) + \
|
||||
@ -141,6 +142,9 @@ qtests_npcm7xx = \
|
||||
'npcm7xx_timer-test',
|
||||
'npcm7xx_watchdog_timer-test']
|
||||
qtests_arm = \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_DUALTIMER') ? ['cmsdk-apb-dualtimer-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_TIMER') ? ['cmsdk-apb-timer-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_CMSDK_APB_WATCHDOG') ? ['cmsdk-apb-watchdog-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_PFLASH_CFI02') ? ['pflash-cfi02-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_NPCM7XX') ? qtests_npcm7xx : []) + \
|
||||
['arm-cpu-features',
|
||||
|
@ -272,7 +272,7 @@ static uint64_t pwm_compute_freq(QTestState *qts, uint32_t ppr, uint32_t csr,
|
||||
|
||||
static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
|
||||
{
|
||||
uint64_t duty;
|
||||
uint32_t duty;
|
||||
|
||||
if (cnr == 0) {
|
||||
/* PWM is stopped. */
|
||||
@ -280,7 +280,7 @@ static uint64_t pwm_compute_duty(uint32_t cnr, uint32_t cmr, bool inverted)
|
||||
} else if (cmr >= cnr) {
|
||||
duty = MAX_DUTY;
|
||||
} else {
|
||||
duty = MAX_DUTY * (cmr + 1) / (cnr + 1);
|
||||
duty = (uint64_t)MAX_DUTY * (cmr + 1) / (cnr + 1);
|
||||
}
|
||||
|
||||
if (inverted) {
|
||||
|
98
tests/qtest/pvpanic-pci-test.c
Normal file
98
tests/qtest/pvpanic-pci-test.c
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* QTest testcase for PV Panic PCI device
|
||||
*
|
||||
* Copyright (C) 2020 Oracle
|
||||
*
|
||||
* Authors:
|
||||
* Mihai Carabas <mihai.carabas@oracle.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqos/libqtest.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "libqos/pci.h"
|
||||
#include "libqos/pci-pc.h"
|
||||
#include "hw/pci/pci_regs.h"
|
||||
|
||||
static void test_panic_nopause(void)
|
||||
{
|
||||
uint8_t val;
|
||||
QDict *response, *data;
|
||||
QTestState *qts;
|
||||
QPCIBus *pcibus;
|
||||
QPCIDevice *dev;
|
||||
QPCIBar bar;
|
||||
|
||||
qts = qtest_init("-device pvpanic-pci,addr=04.0 -action panic=none");
|
||||
pcibus = qpci_new_pc(qts, NULL);
|
||||
dev = qpci_device_find(pcibus, QPCI_DEVFN(0x4, 0x0));
|
||||
qpci_device_enable(dev);
|
||||
bar = qpci_iomap(dev, 0, NULL);
|
||||
|
||||
qpci_memread(dev, bar, 0, &val, sizeof(val));
|
||||
g_assert_cmpuint(val, ==, 3);
|
||||
|
||||
val = 1;
|
||||
qpci_memwrite(dev, bar, 0, &val, sizeof(val));
|
||||
|
||||
response = qtest_qmp_eventwait_ref(qts, "GUEST_PANICKED");
|
||||
g_assert(qdict_haskey(response, "data"));
|
||||
data = qdict_get_qdict(response, "data");
|
||||
g_assert(qdict_haskey(data, "action"));
|
||||
g_assert_cmpstr(qdict_get_str(data, "action"), ==, "run");
|
||||
qobject_unref(response);
|
||||
|
||||
g_free(dev);
|
||||
qpci_free_pc(pcibus);
|
||||
qtest_quit(qts);
|
||||
}
|
||||
|
||||
static void test_panic(void)
|
||||
{
|
||||
uint8_t val;
|
||||
QDict *response, *data;
|
||||
QTestState *qts;
|
||||
QPCIBus *pcibus;
|
||||
QPCIDevice *dev;
|
||||
QPCIBar bar;
|
||||
|
||||
qts = qtest_init("-device pvpanic-pci,addr=04.0 -action panic=pause");
|
||||
pcibus = qpci_new_pc(qts, NULL);
|
||||
dev = qpci_device_find(pcibus, QPCI_DEVFN(0x4, 0x0));
|
||||
qpci_device_enable(dev);
|
||||
bar = qpci_iomap(dev, 0, NULL);
|
||||
|
||||
qpci_memread(dev, bar, 0, &val, sizeof(val));
|
||||
g_assert_cmpuint(val, ==, 3);
|
||||
|
||||
val = 1;
|
||||
qpci_memwrite(dev, bar, 0, &val, sizeof(val));
|
||||
|
||||
response = qtest_qmp_eventwait_ref(qts, "GUEST_PANICKED");
|
||||
g_assert(qdict_haskey(response, "data"));
|
||||
data = qdict_get_qdict(response, "data");
|
||||
g_assert(qdict_haskey(data, "action"));
|
||||
g_assert_cmpstr(qdict_get_str(data, "action"), ==, "pause");
|
||||
qobject_unref(response);
|
||||
|
||||
g_free(dev);
|
||||
qpci_free_pc(pcibus);
|
||||
qtest_quit(qts);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
qtest_add_func("/pvpanic-pci/panic", test_panic);
|
||||
qtest_add_func("/pvpanic-pci/panic-nopause", test_panic_nopause);
|
||||
|
||||
ret = g_test_run();
|
||||
|
||||
return ret;
|
||||
}
|
@ -138,9 +138,9 @@ static void test_can_bus(void)
|
||||
uint8_t can_timestamp = 1;
|
||||
|
||||
QTestState *qts = qtest_init("-machine xlnx-zcu102"
|
||||
" -object can-bus,id=canbus0"
|
||||
" -machine xlnx-zcu102.canbus0=canbus0"
|
||||
" -machine xlnx-zcu102.canbus1=canbus0"
|
||||
" -object can-bus,id=canbus"
|
||||
" -machine canbus0=canbus"
|
||||
" -machine canbus1=canbus"
|
||||
);
|
||||
|
||||
/* Configure the CAN0 and CAN1. */
|
||||
@ -175,9 +175,9 @@ static void test_can_loopback(void)
|
||||
uint32_t status = 0;
|
||||
|
||||
QTestState *qts = qtest_init("-machine xlnx-zcu102"
|
||||
" -object can-bus,id=canbus0"
|
||||
" -machine xlnx-zcu102.canbus0=canbus0"
|
||||
" -machine xlnx-zcu102.canbus1=canbus0"
|
||||
" -object can-bus,id=canbus"
|
||||
" -machine canbus0=canbus"
|
||||
" -machine canbus1=canbus"
|
||||
);
|
||||
|
||||
/* Configure the CAN0 in loopback mode. */
|
||||
@ -223,9 +223,9 @@ static void test_can_filter(void)
|
||||
uint8_t can_timestamp = 1;
|
||||
|
||||
QTestState *qts = qtest_init("-machine xlnx-zcu102"
|
||||
" -object can-bus,id=canbus0"
|
||||
" -machine xlnx-zcu102.canbus0=canbus0"
|
||||
" -machine xlnx-zcu102.canbus1=canbus0"
|
||||
" -object can-bus,id=canbus"
|
||||
" -machine canbus0=canbus"
|
||||
" -machine canbus1=canbus"
|
||||
);
|
||||
|
||||
/* Configure the CAN0 and CAN1. */
|
||||
@ -271,9 +271,9 @@ static void test_can_sleepmode(void)
|
||||
uint8_t can_timestamp = 1;
|
||||
|
||||
QTestState *qts = qtest_init("-machine xlnx-zcu102"
|
||||
" -object can-bus,id=canbus0"
|
||||
" -machine xlnx-zcu102.canbus0=canbus0"
|
||||
" -machine xlnx-zcu102.canbus1=canbus0"
|
||||
" -object can-bus,id=canbus"
|
||||
" -machine canbus0=canbus"
|
||||
" -machine canbus1=canbus"
|
||||
);
|
||||
|
||||
/* Configure the CAN0. */
|
||||
@ -317,9 +317,9 @@ static void test_can_snoopmode(void)
|
||||
uint8_t can_timestamp = 1;
|
||||
|
||||
QTestState *qts = qtest_init("-machine xlnx-zcu102"
|
||||
" -object can-bus,id=canbus0"
|
||||
" -machine xlnx-zcu102.canbus0=canbus0"
|
||||
" -machine xlnx-zcu102.canbus1=canbus0"
|
||||
" -object can-bus,id=canbus"
|
||||
" -machine canbus0=canbus"
|
||||
" -machine canbus1=canbus"
|
||||
);
|
||||
|
||||
/* Configure the CAN0. */
|
||||
|
Loading…
Reference in New Issue
Block a user