diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-01-29 17:22:52 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-01-29 17:22:53 +0000 |
commit | 9df52f58e76e904fb141b10318362d718f470db2 (patch) | |
tree | ea3d1eaa9724304ba2b634c3af34f76537331ea2 /hw | |
parent | 3701c07e63bb945137bf80fe35e7058ad3784c45 (diff) | |
parent | 14711b6f54708b9583796db02b12ee7bd0331502 (diff) | |
download | qemu-9df52f58e76e904fb141b10318362d718f470db2.zip qemu-9df52f58e76e904fb141b10318362d718f470db2.tar.gz qemu-9df52f58e76e904fb141b10318362d718f470db2.tar.bz2 |
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>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/Kconfig | 1 | ||||
-rw-r--r-- | hw/arm/armsse.c | 48 | ||||
-rw-r--r-- | hw/arm/mps2-tz.c | 14 | ||||
-rw-r--r-- | hw/arm/mps2.c | 28 | ||||
-rw-r--r-- | hw/arm/musca.c | 13 | ||||
-rw-r--r-- | hw/arm/stellaris.c | 170 | ||||
-rw-r--r-- | hw/arm/virt.c | 111 | ||||
-rw-r--r-- | hw/arm/xlnx-zcu102.c | 4 | ||||
-rw-r--r-- | hw/core/ptimer.c | 34 | ||||
-rw-r--r-- | hw/gpio/Kconfig | 3 | ||||
-rw-r--r-- | hw/gpio/gpio_pwr.c | 70 | ||||
-rw-r--r-- | hw/gpio/meson.build | 1 | ||||
-rw-r--r-- | hw/i386/Kconfig | 2 | ||||
-rw-r--r-- | hw/misc/Kconfig | 12 | ||||
-rw-r--r-- | hw/misc/meson.build | 4 | ||||
-rw-r--r-- | hw/misc/npcm7xx_pwm.c | 23 | ||||
-rw-r--r-- | hw/misc/pvpanic-isa.c | 94 | ||||
-rw-r--r-- | hw/misc/pvpanic-pci.c | 94 | ||||
-rw-r--r-- | hw/misc/pvpanic.c | 85 | ||||
-rw-r--r-- | hw/timer/cmsdk-apb-dualtimer.c | 53 | ||||
-rw-r--r-- | hw/timer/cmsdk-apb-timer.c | 55 | ||||
-rw-r--r-- | hw/watchdog/cmsdk-apb-watchdog.c | 29 |
22 files changed, 730 insertions, 218 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 0a242e4..13cc42d 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -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 diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index baac027..26e1a8c 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -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() } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 3707876..90caa91 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -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); /* diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 9a8b23c..39add41 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -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)); diff --git a/hw/arm/musca.c b/hw/arm/musca.c index b50157f..945643c 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -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. diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 6528231..ad72c09 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -26,6 +26,7 @@ #include "hw/watchdog/cmsdk-apb-watchdog.h" #include "migration/vmstate.h" #include "hw/misc/unimp.h" +#include "hw/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) -{ - ssys_state *s; +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() +}; - 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); +static void stellaris_sys_instance_init(Object *obj) +{ + ssys_state *s = STELLARIS_SYS(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(s); - 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) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 86070df..399da73 100644 --- a/hw/arm/virt.c +++ b/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) diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4ef0c51..c971363 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -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); diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 2aa97cb..6ba19fd 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -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) { diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig index b6fdaa2..f0e7405 100644 --- a/hw/gpio/Kconfig +++ b/hw/gpio/Kconfig @@ -8,5 +8,8 @@ config PL061 config GPIO_KEY bool +config GPIO_PWR + bool + config SIFIVE_GPIO bool diff --git a/hw/gpio/gpio_pwr.c b/hw/gpio/gpio_pwr.c new file mode 100644 index 0000000..7714fa0 --- /dev/null +++ b/hw/gpio/gpio_pwr.c @@ -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) diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 5c0a7d7..79568f0 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -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')) diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index eea059f..7f91f30 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -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 diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index cf18ac0..19c216f 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -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 diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 607cd38..6292839 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -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')) diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c index e99e3cc..dabcb6c 100644 --- a/hw/misc/npcm7xx_pwm.c +++ b/hw/misc/npcm7xx_pwm.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; diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c new file mode 100644 index 0000000..27113ab --- /dev/null +++ b/hw/misc/pvpanic-isa.c @@ -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) diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c new file mode 100644 index 0000000..d629639 --- /dev/null +++ b/hw/misc/pvpanic-pci.c @@ -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); diff --git a/hw/misc/pvpanic.c b/hw/misc/pvpanic.c index 35d6797..e2cb4a5 100644 --- a/hw/misc/pvpanic.c +++ b/hw/misc/pvpanic.c @@ -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) -{ - PVPanicState *s = ISA_PVPANIC_DEVICE(obj); - - memory_region_init_io(&s->io, OBJECT(s), &pvpanic_ops, s, "pvpanic", 1); -} - -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) +void pvpanic_setup_io(PVPanicState *s, DeviceState *dev, unsigned size) { - 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); + memory_region_init_io(&s->mr, OBJECT(dev), &pvpanic_ops, s, "pvpanic", size); } - -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) diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c index f653424..ef49f58 100644 --- a/hw/timer/cmsdk-apb-dualtimer.c +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -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 = { diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c index f85f130..ee51ce3 100644 --- a/hw/timer/cmsdk-apb-timer.c +++ b/hw/timer/cmsdk-apb-timer.c @@ -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, }; diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index 5bbadad..302f171 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -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 = { |