diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-09-04 17:21:24 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-09-04 17:21:24 +0100 |
commit | 2b483739791b33c46e6084b51edcf62107058ae1 (patch) | |
tree | fab8d4164ff9c0a73fdaad41ee06815d6163e504 /hw | |
parent | 98bfaac788be0ca63d7d010c8d4ba100ff1d8278 (diff) | |
parent | 7229ec5825df6b933f150b54a8a2bedd2de1864c (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20170904-2' into staging
target-arm:
* collection of M profile cleanups and minor bugfixes
* loader: handle ELF files with overlapping zero-init data
* virt: allow PMU instantiation with userspace irqchip
* wdt_aspeed: Add support for the reset width register
* cpu: Define new cpu_transaction_failed() hook
* Mark some SoC devices as not user-creatable
* arm: Fix aa64 ldp register writeback
* arm_gicv3_kvm: Fix compile warning
# gpg: Signature made Mon 04 Sep 2017 17:20:40 BST
# gpg: using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg: aka "Peter Maydell <pmaydell@gmail.com>"
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20170904-2: (33 commits)
arm_gicv3_kvm: Fix compile warning
target/arm: Fix aa64 ldp register writeback
hw/arm/digic: Mark device with user_creatable = false
hw/arm/aspeed_soc: Mark devices as user_creatable = false
target/arm: Allow deliver_fault() caller to specify EA bit
target/arm: Factor out fault delivery code
cputlb: Support generating CPU exceptions on memory transaction failures
cpu: Define new cpu_transaction_failed() hook
memory.h: Move MemTxResult type to memattrs.h
aspeed_soc: Propagate silicon-rev to watchdog
watchdog: wdt_aspeed: Add support for the reset width register
target/arm/kvm: pmu: improve error handling
hw/arm/virt: allow pmu instantiation with userspace irqchip
target/arm/kvm: pmu: split init and set-irq stages
hw/arm/virt: add pmu interrupt state
hw/arm: use defined type name instead of hard-coded string
loader: Ignore zero-sized ELF segments
loader: Handle ELF files with overlapping zero-initialized data
nvic: Implement "user accesses BusFault" SCS region behaviour
armv7m_nvic.h: Move from include/hw/arm to include/hw/intc
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/armv7m.c | 4 | ||||
-rw-r--r-- | hw/arm/aspeed_soc.c | 4 | ||||
-rw-r--r-- | hw/arm/digic.c | 2 | ||||
-rw-r--r-- | hw/arm/exynos4210.c | 4 | ||||
-rw-r--r-- | hw/arm/highbank.c | 11 | ||||
-rw-r--r-- | hw/arm/realview.c | 6 | ||||
-rw-r--r-- | hw/arm/vexpress.c | 6 | ||||
-rw-r--r-- | hw/arm/virt.c | 12 | ||||
-rw-r--r-- | hw/arm/xilinx_zynq.c | 14 | ||||
-rw-r--r-- | hw/intc/arm_gicv3_kvm.c | 2 | ||||
-rw-r--r-- | hw/intc/armv7m_nvic.c | 68 | ||||
-rw-r--r-- | hw/watchdog/wdt_aspeed.c | 93 |
12 files changed, 170 insertions, 56 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index c8a11f2b53..d2477e84e4 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -146,7 +146,7 @@ static void armv7m_instance_init(Object *obj) &error_abort); memory_region_init(&s->container, obj, "armv7m-container", UINT64_MAX); - object_initialize(&s->nvic, sizeof(s->nvic), "armv7m_nvic"); + object_initialize(&s->nvic, sizeof(s->nvic), TYPE_NVIC); qdev_set_parent_bus(DEVICE(&s->nvic), sysbus_get_default()); object_property_add_alias(obj, "num-irq", OBJECT(&s->nvic), "num-irq", &error_abort); @@ -293,7 +293,7 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq, cpu_model = "cortex-m3"; } - armv7m = qdev_create(NULL, "armv7m"); + armv7m = qdev_create(NULL, TYPE_ARMV7M); qdev_prop_set_uint32(armv7m, "num-irq", num_irq); qdev_prop_set_string(armv7m, "cpu-model", cpu_model); object_property_set_link(OBJECT(armv7m), OBJECT(get_system_memory()), diff --git a/hw/arm/aspeed_soc.c b/hw/arm/aspeed_soc.c index 5529024edf..13c6393350 100644 --- a/hw/arm/aspeed_soc.c +++ b/hw/arm/aspeed_soc.c @@ -183,6 +183,8 @@ static void aspeed_soc_init(Object *obj) object_initialize(&s->wdt[i], sizeof(s->wdt[i]), TYPE_ASPEED_WDT); object_property_add_child(obj, "wdt[*]", OBJECT(&s->wdt[i]), NULL); qdev_set_parent_bus(DEVICE(&s->wdt[i]), sysbus_get_default()); + qdev_prop_set_uint32(DEVICE(&s->wdt[i]), "silicon-rev", + sc->info->silicon_rev); } object_initialize(&s->ftgmac100, sizeof(s->ftgmac100), TYPE_FTGMAC100); @@ -338,6 +340,8 @@ static void aspeed_soc_class_init(ObjectClass *oc, void *data) sc->info = (AspeedSoCInfo *) data; dc->realize = aspeed_soc_realize; + /* Reason: Uses serial_hds and nd_table in realize() directly */ + dc->user_creatable = false; } static const TypeInfo aspeed_soc_type_info = { diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 94f32637f0..6184020985 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -101,6 +101,8 @@ static void digic_class_init(ObjectClass *oc, void *data) DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = digic_realize; + /* Reason: Uses serial_hds in the realize function --> not usable twice */ + dc->user_creatable = false; } static const TypeInfo digic_type_info = { diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index f9e79f3ebb..ee1438a0f4 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -33,7 +33,7 @@ #include "hw/arm/arm.h" #include "hw/loader.h" #include "hw/arm/exynos4210.h" -#include "hw/sd/sd.h" +#include "hw/sd/sdhci.h" #include "hw/usb/hcd-ehci.h" #define EXYNOS4210_CHIPID_ADDR 0x10000000 @@ -381,7 +381,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem) BlockBackend *blk; DriveInfo *di; - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_prop_set_uint32(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); qdev_init_nofail(dev); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 20e60f15c4..942d5a82b9 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -31,6 +31,9 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" +#include "hw/ide/ahci.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/cpu/a15mpcore.h" #define SMP_BOOT_ADDR 0x100 #define SMP_BOOT_REG 0x40 @@ -300,10 +303,10 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff12000); - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); break; case CALXEDA_MIDWAY: - dev = qdev_create(NULL, "a15mpcore_priv"); + dev = qdev_create(NULL, TYPE_A15MPCORE_PRIV); break; } qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); @@ -329,7 +332,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) sysbus_connect_irq(busdev, 0, pic[18]); pl011_create(0xfff36000, pic[20], serial_hds[0]); - dev = qdev_create(NULL, "highbank-regs"); + dev = qdev_create(NULL, TYPE_HIGHBANK_REGISTERS); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); sysbus_mmio_map(busdev, 0, 0xfff3c000); @@ -341,7 +344,7 @@ static void calxeda_init(MachineState *machine, enum cxmachines machine_id) sysbus_create_simple("pl031", 0xfff35000, pic[19]); sysbus_create_simple("pl022", 0xfff39000, pic[23]); - sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]); + sysbus_create_simple(TYPE_SYSBUS_AHCI, 0xffe08000, pic[83]); if (nd_table[0].used) { qemu_check_nic_model(&nd_table[0], "xgmac"); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 76ff5579bc..273615652c 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -24,6 +24,8 @@ #include "exec/address-spaces.h" #include "qemu/error-report.h" #include "hw/char/pl011.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/intc/realview_gic.h" #define SMP_BOOT_ADDR 0xe0000000 #define SMP_BOOTREG_ADDR 0x10000030 @@ -172,7 +174,7 @@ static void realview_init(MachineState *machine, sysbus_mmio_map(SYS_BUS_DEVICE(sysctl), 0, 0x10000000); if (is_mpcore) { - dev = qdev_create(NULL, is_pb ? "a9mpcore_priv": "realview_mpcore"); + dev = qdev_create(NULL, is_pb ? TYPE_A9MPCORE_PRIV : "realview_mpcore"); qdev_prop_set_uint32(dev, "num-cpu", smp_cpus); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -186,7 +188,7 @@ static void realview_init(MachineState *machine, } else { uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000; /* For now just create the nIRQ GIC, and ignore the others. */ - dev = sysbus_create_simple("realview_gic", gic_addr, cpu_irq[0]); + dev = sysbus_create_simple(TYPE_REALVIEW_GIC, gic_addr, cpu_irq[0]); } for (n = 0; n < 64; n++) { pic[n] = qdev_get_gpio_in(dev, n); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 528c65ddb6..571dd3609a 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -40,6 +40,8 @@ #include "qemu/error-report.h" #include <libfdt.h> #include "hw/char/pl011.h" +#include "hw/cpu/a9mpcore.h" +#include "hw/cpu/a15mpcore.h" #define VEXPRESS_BOARD_ID 0x8e0 #define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024) @@ -293,7 +295,7 @@ static void a9_daughterboard_init(const VexpressMachineState *vms, memory_region_add_subregion(sysmem, 0x60000000, ram); /* 0x1e000000 A9MPCore (SCU) private memory region */ - init_cpus(cpu_model, "a9mpcore_priv", 0x1e000000, pic, vms->secure); + init_cpus(cpu_model, TYPE_A9MPCORE_PRIV, 0x1e000000, pic, vms->secure); /* Daughterboard peripherals : 0x10020000 .. 0x20000000 */ @@ -378,7 +380,7 @@ static void a15_daughterboard_init(const VexpressMachineState *vms, memory_region_add_subregion(sysmem, 0x80000000, ram); /* 0x2c000000 A15MPCore private memory region (GIC) */ - init_cpus(cpu_model, "a15mpcore_priv", 0x2c000000, pic, vms->secure); + init_cpus(cpu_model, TYPE_A15MPCORE_PRIV, 0x2c000000, pic, vms->secure); /* A15 daughterboard peripherals: */ diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 6b7a0fefc4..fe96557997 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -492,10 +492,15 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms) CPU_FOREACH(cpu) { armcpu = ARM_CPU(cpu); - if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU) || - (kvm_enabled() && !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ)))) { + if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) { return; } + if (kvm_enabled()) { + if (kvm_irqchip_in_kernel()) { + kvm_arm_pmu_set_irq(cpu, PPI(VIRTUAL_PMU_IRQ)); + } + kvm_arm_pmu_init(cpu); + } } if (vms->gic_version == 2) { @@ -610,6 +615,9 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic) qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0, qdev_get_gpio_in(gicdev, ppibase + ARCH_GICV3_MAINT_IRQ)); + qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0, + qdev_get_gpio_in(gicdev, ppibase + + VIRTUAL_PMU_IRQ)); sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ)); sysbus_connect_irq(gicbusdev, i + smp_cpus, diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 6b11a75e67..a750959d45 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -31,8 +31,10 @@ #include "hw/misc/zynq-xadc.h" #include "hw/ssi/ssi.h" #include "qemu/error-report.h" -#include "hw/sd/sd.h" +#include "hw/sd/sdhci.h" #include "hw/char/cadence_uart.h" +#include "hw/net/cadence_gem.h" +#include "hw/cpu/a9mpcore.h" #define NUM_SPI_FLASHES 4 #define NUM_QSPI_FLASHES 2 @@ -96,9 +98,9 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "cadence_gem"); + dev = qdev_create(NULL, TYPE_CADENCE_GEM); if (nd->used) { - qemu_check_nic_model(nd, "cadence_gem"); + qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(dev, nd); } qdev_init_nofail(dev); @@ -222,7 +224,7 @@ static void zynq_init(MachineState *machine) qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xF8000000); - dev = qdev_create(NULL, "a9mpcore_priv"); + dev = qdev_create(NULL, TYPE_A9MPCORE_PRIV); qdev_prop_set_uint32(dev, "num-cpu", 1); qdev_init_nofail(dev); busdev = SYS_BUS_DEVICE(dev); @@ -252,7 +254,7 @@ static void zynq_init(MachineState *machine) gem_init(&nd_table[0], 0xE000B000, pic[54-IRQ_OFFSET]); gem_init(&nd_table[1], 0xE000C000, pic[77-IRQ_OFFSET]); - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0100000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); @@ -263,7 +265,7 @@ static void zynq_init(MachineState *machine) qdev_prop_set_drive(carddev, "drive", blk, &error_fatal); object_property_set_bool(OBJECT(carddev), true, "realized", &error_fatal); - dev = qdev_create(NULL, "generic-sdhci"); + dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); qdev_init_nofail(dev); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 6051c77705..481fe5405a 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -293,7 +293,7 @@ static void kvm_arm_gicv3_put(GICv3State *s) kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, true); reg64 = c->gicr_pendbaser; - if (!c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) { + if (!(c->gicr_ctlr & GICR_CTLR_ENABLE_LPIS)) { /* Setting PTZ is advised if LPIs are disabled, to reduce * GIC initialization time. */ diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 323e2d47aa..bbfe2d55be 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -17,7 +17,7 @@ #include "hw/sysbus.h" #include "qemu/timer.h" #include "hw/arm/arm.h" -#include "hw/arm/armv7m_nvic.h" +#include "hw/intc/armv7m_nvic.h" #include "target/arm/cpu.h" #include "exec/exec-all.h" #include "qemu/log.h" @@ -167,9 +167,9 @@ static inline int nvic_exec_prio(NVICState *s) CPUARMState *env = &s->cpu->env; int running; - if (env->daif & PSTATE_F) { /* FAULTMASK */ + if (env->v7m.faultmask) { running = -1; - } else if (env->daif & PSTATE_I) { /* PRIMASK */ + } else if (env->v7m.primask) { running = 0; } else if (env->v7m.basepri > 0) { running = env->v7m.basepri & nvic_gprio_mask(s); @@ -733,11 +733,8 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value) } case 0xf00: /* Software Triggered Interrupt Register */ { - /* user mode can only write to STIR if CCR.USERSETMPEND permits it */ int excnum = (value & 0x1ff) + NVIC_FIRST_IRQ; - if (excnum < s->num_irq && - (arm_current_el(&cpu->env) || - (cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) { + if (excnum < s->num_irq) { armv7m_nvic_set_pending(s, excnum); } break; @@ -748,14 +745,32 @@ static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value) } } -static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, - unsigned size) +static bool nvic_user_access_ok(NVICState *s, hwaddr offset) +{ + /* Return true if unprivileged access to this register is permitted. */ + switch (offset) { + case 0xf00: /* STIR: accessible only if CCR.USERSETMPEND permits */ + return s->cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK; + default: + /* All other user accesses cause a BusFault unconditionally */ + return false; + } +} + +static MemTxResult nvic_sysreg_read(void *opaque, hwaddr addr, + uint64_t *data, unsigned size, + MemTxAttrs attrs) { NVICState *s = (NVICState *)opaque; uint32_t offset = addr; unsigned i, startvec, end; uint32_t val; + if (attrs.user && !nvic_user_access_ok(s, addr)) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + switch (offset) { /* reads of set and clear both return the status */ case 0x100 ... 0x13f: /* NVIC Set enable */ @@ -826,11 +841,13 @@ static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, } trace_nvic_sysreg_read(addr, val, size); - return val; + *data = val; + return MEMTX_OK; } -static void nvic_sysreg_write(void *opaque, hwaddr addr, - uint64_t value, unsigned size) +static MemTxResult nvic_sysreg_write(void *opaque, hwaddr addr, + uint64_t value, unsigned size, + MemTxAttrs attrs) { NVICState *s = (NVICState *)opaque; uint32_t offset = addr; @@ -839,6 +856,11 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, trace_nvic_sysreg_write(addr, value, size); + if (attrs.user && !nvic_user_access_ok(s, addr)) { + /* Generate BusFault for unprivileged accesses */ + return MEMTX_ERROR; + } + switch (offset) { case 0x100 ... 0x13f: /* NVIC Set enable */ offset += 0x80; @@ -853,7 +875,7 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return; + return MEMTX_OK; case 0x200 ... 0x23f: /* NVIC Set pend */ /* the special logic in armv7m_nvic_set_pending() * is not needed since IRQs are never escalated @@ -870,9 +892,9 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, } } nvic_irq_update(s); - return; + return MEMTX_OK; case 0x300 ... 0x33f: /* NVIC Active */ - return; /* R/O */ + return MEMTX_OK; /* R/O */ case 0x400 ... 0x5ef: /* NVIC Priority */ startvec = 8 * (offset - 0x400) + NVIC_FIRST_IRQ; /* vector # */ @@ -880,26 +902,28 @@ static void nvic_sysreg_write(void *opaque, hwaddr addr, set_prio(s, startvec + i, (value >> (i * 8)) & 0xff); } nvic_irq_update(s); - return; + return MEMTX_OK; case 0xd18 ... 0xd23: /* System Handler Priority. */ for (i = 0; i < size; i++) { unsigned hdlidx = (offset - 0xd14) + i; set_prio(s, hdlidx, (value >> (i * 8)) & 0xff); } nvic_irq_update(s); - return; + return MEMTX_OK; } if (size == 4) { nvic_writel(s, offset, value); - return; + return MEMTX_OK; } qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad write of size %d at offset 0x%x\n", size, offset); + /* This is UNPREDICTABLE; treat as RAZ/WI */ + return MEMTX_OK; } static const MemoryRegionOps nvic_sysreg_ops = { - .read = nvic_sysreg_read, - .write = nvic_sysreg_write, + .read_with_attrs = nvic_sysreg_read, + .write_with_attrs = nvic_sysreg_write, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -1036,10 +1060,6 @@ static void armv7m_nvic_realize(DeviceState *dev, Error **errp) * 0xd00..0xd3c - SCS registers * 0xd40..0xeff - Reserved or Not implemented * 0xf00 - STIR - * - * At the moment there is only one thing in the container region, - * but we leave it in place to allow us to pull systick out into - * its own device object later. */ memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000); /* The system register region goes at the bottom of the priority diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index 8bbe579b6b..22bce364d7 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -8,16 +8,19 @@ */ #include "qemu/osdep.h" + +#include "qapi/error.h" #include "qemu/log.h" +#include "qemu/timer.h" #include "sysemu/watchdog.h" +#include "hw/misc/aspeed_scu.h" #include "hw/sysbus.h" -#include "qemu/timer.h" #include "hw/watchdog/wdt_aspeed.h" -#define WDT_STATUS (0x00 / 4) -#define WDT_RELOAD_VALUE (0x04 / 4) -#define WDT_RESTART (0x08 / 4) -#define WDT_CTRL (0x0C / 4) +#define WDT_STATUS (0x00 / 4) +#define WDT_RELOAD_VALUE (0x04 / 4) +#define WDT_RESTART (0x08 / 4) +#define WDT_CTRL (0x0C / 4) #define WDT_CTRL_RESET_MODE_SOC (0x00 << 5) #define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5) #define WDT_CTRL_1MHZ_CLK BIT(4) @@ -25,18 +28,41 @@ #define WDT_CTRL_WDT_INTR BIT(2) #define WDT_CTRL_RESET_SYSTEM BIT(1) #define WDT_CTRL_ENABLE BIT(0) +#define WDT_RESET_WIDTH (0x18 / 4) +#define WDT_RESET_WIDTH_ACTIVE_HIGH BIT(31) +#define WDT_POLARITY_MASK (0xFF << 24) +#define WDT_ACTIVE_HIGH_MAGIC (0xA5 << 24) +#define WDT_ACTIVE_LOW_MAGIC (0x5A << 24) +#define WDT_RESET_WIDTH_PUSH_PULL BIT(30) +#define WDT_DRIVE_TYPE_MASK (0xFF << 24) +#define WDT_PUSH_PULL_MAGIC (0xA8 << 24) +#define WDT_OPEN_DRAIN_MAGIC (0x8A << 24) -#define WDT_TIMEOUT_STATUS (0x10 / 4) -#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESET_WDITH (0x18 / 4) +#define WDT_TIMEOUT_STATUS (0x10 / 4) +#define WDT_TIMEOUT_CLEAR (0x14 / 4) -#define WDT_RESTART_MAGIC 0x4755 +#define WDT_RESTART_MAGIC 0x4755 static bool aspeed_wdt_is_enabled(const AspeedWDTState *s) { return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE; } +static bool is_ast2500(const AspeedWDTState *s) +{ + switch (s->silicon_rev) { + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + return true; + case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: + default: + break; + } + + return false; +} + static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) { AspeedWDTState *s = ASPEED_WDT(opaque); @@ -55,9 +81,10 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size) return 0; case WDT_CTRL: return s->regs[WDT_CTRL]; + case WDT_RESET_WIDTH: + return s->regs[WDT_RESET_WIDTH]; case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: - case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -119,9 +146,27 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, timer_del(s->timer); } break; + case WDT_RESET_WIDTH: + { + uint32_t property = data & WDT_POLARITY_MASK; + + if (property && is_ast2500(s)) { + if (property == WDT_ACTIVE_HIGH_MAGIC) { + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_ACTIVE_HIGH; + } else if (property == WDT_ACTIVE_LOW_MAGIC) { + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_ACTIVE_HIGH; + } else if (property == WDT_PUSH_PULL_MAGIC) { + s->regs[WDT_RESET_WIDTH] |= WDT_RESET_WIDTH_PUSH_PULL; + } else if (property == WDT_OPEN_DRAIN_MAGIC) { + s->regs[WDT_RESET_WIDTH] &= ~WDT_RESET_WIDTH_PUSH_PULL; + } + } + s->regs[WDT_RESET_WIDTH] &= ~s->ext_pulse_width_mask; + s->regs[WDT_RESET_WIDTH] |= data & s->ext_pulse_width_mask; + break; + } case WDT_TIMEOUT_STATUS: case WDT_TIMEOUT_CLEAR: - case WDT_RESET_WDITH: qemu_log_mask(LOG_UNIMP, "%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -167,6 +212,7 @@ static void aspeed_wdt_reset(DeviceState *dev) s->regs[WDT_RELOAD_VALUE] = 0x03EF1480; s->regs[WDT_RESTART] = 0; s->regs[WDT_CTRL] = 0; + s->regs[WDT_RESET_WIDTH] = 0xFF; timer_del(s->timer); } @@ -187,6 +233,25 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) SysBusDevice *sbd = SYS_BUS_DEVICE(dev); AspeedWDTState *s = ASPEED_WDT(dev); + if (!is_supported_silicon_rev(s->silicon_rev)) { + error_setg(errp, "Unknown silicon revision: 0x%" PRIx32, + s->silicon_rev); + return; + } + + switch (s->silicon_rev) { + case AST2400_A0_SILICON_REV: + case AST2400_A1_SILICON_REV: + s->ext_pulse_width_mask = 0xff; + break; + case AST2500_A0_SILICON_REV: + case AST2500_A1_SILICON_REV: + s->ext_pulse_width_mask = 0xfffff; + break; + default: + g_assert_not_reached(); + } + s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev); /* FIXME: This setting should be derived from the SCU hw strapping @@ -199,6 +264,11 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } +static Property aspeed_wdt_properties[] = { + DEFINE_PROP_UINT32("silicon-rev", AspeedWDTState, silicon_rev, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void aspeed_wdt_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -207,6 +277,7 @@ static void aspeed_wdt_class_init(ObjectClass *klass, void *data) dc->reset = aspeed_wdt_reset; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->vmsd = &vmstate_aspeed_wdt; + dc->props = aspeed_wdt_properties; } static const TypeInfo aspeed_wdt_info = { |