diff options
author | Peter Maydell | 2021-01-29 18:22:52 +0100 |
---|---|---|
committer | Peter Maydell | 2021-01-29 18:22:53 +0100 |
commit | 9df52f58e76e904fb141b10318362d718f470db2 (patch) | |
tree | ea3d1eaa9724304ba2b634c3af34f76537331ea2 /hw/arm | |
parent | Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging (diff) | |
parent | hw/arm/stellaris: Remove board-creation reset of STELLARIS_SYS (diff) | |
download | qemu-9df52f58e76e904fb141b10318362d718f470db2.tar.gz qemu-9df52f58e76e904fb141b10318362d718f470db2.tar.xz qemu-9df52f58e76e904fb141b10318362d718f470db2.zip |
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/arm')
-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 |
8 files changed, 304 insertions, 85 deletions
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 0a242e4c5d..13cc42dcc8 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 baac027659..26e1a8c95b 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 3707876d6d..90caa91493 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 9a8b23c64c..39add416db 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 b50157f63a..945643c3cd 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 652823195b..ad72c0959f 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 86070dfd98..399da73454 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 4ef0c516bf..c9713638c5 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); |