* [PATCH v4 0/3] Implement the watchdog timer of HiFive 1 rev b.
@ 2023-05-23 8:49 Tommy Wu
2023-05-23 8:49 ` [PATCH v4 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Tommy Wu @ 2023-05-23 8:49 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei, Tommy Wu
The HiFive 1 rev b includes a watchdog module based on a 32-bit
counter. The watchdog timer is in the always-on domain device of
HiFive 1 rev b, so this patch added the AON device to the sifive_e
machine. This patch only implemented the functionality of the
watchdog timer, not all the functionality of the AON device.
You can test the patchset by the QTest tests/qtest/sifive-e-aon-watchdog-test.c
Changes since v1 ( Thank Alistair for the feedback ):
- Use the register field macro.
- Delete the public create function. The board creates the aon device itself.
- Keep all variable declarations at the top of the code block.
Changes since v2 ( Thank Alistair for the feedback ):
- Delete the declaration and definition of the create function.
Changes since v3 ( Thank Alistair and Thomas for the feedback ):
- Use `device_class_set_props()` for the properties in sifive_e_aon device.
- Add SPDX identifier in QTEST.
- Use libqtest.h in QTEST.
- Let the statements on one line as long as they still fit into 80 columns.
Tommy Wu (3):
hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of
sifive_e
hw/misc/Kconfig | 3 +
hw/misc/meson.build | 1 +
hw/misc/sifive_e_aon.c | 326 ++++++++++++++++
hw/riscv/Kconfig | 1 +
hw/riscv/sifive_e.c | 13 +-
include/hw/misc/sifive_e_aon.h | 60 +++
include/hw/riscv/sifive_e.h | 8 +-
tests/qtest/meson.build | 3 +
tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
9 files changed, 860 insertions(+), 5 deletions(-)
create mode 100644 hw/misc/sifive_e_aon.c
create mode 100644 include/hw/misc/sifive_e_aon.h
create mode 100644 tests/qtest/sifive-e-aon-watchdog-test.c
--
2.27.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/3] hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
2023-05-23 8:49 [PATCH v4 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
@ 2023-05-23 8:49 ` Tommy Wu
2023-05-25 12:05 ` Philippe Mathieu-Daudé
2023-05-23 8:49 ` [PATCH v4 2/3] hw/riscv: sifive_e: " Tommy Wu
2023-05-23 8:49 ` [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
2 siblings, 1 reply; 9+ messages in thread
From: Tommy Wu @ 2023-05-23 8:49 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei, Tommy Wu
The watchdog timer is in the always-on domain device of HiFive 1 rev b,
so this patch added the AON device to the sifive_e machine. This patch
only implemented the functionality of the watchdog timer.
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
---
hw/misc/Kconfig | 3 +
hw/misc/meson.build | 1 +
hw/misc/sifive_e_aon.c | 326 +++++++++++++++++++++++++++++++++
include/hw/misc/sifive_e_aon.h | 60 ++++++
4 files changed, 390 insertions(+)
create mode 100644 hw/misc/sifive_e_aon.c
create mode 100644 include/hw/misc/sifive_e_aon.h
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 2ef5781ef8..10d367d616 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -158,6 +158,9 @@ config SIFIVE_TEST
config SIFIVE_E_PRCI
bool
+config SIFIVE_E_AON
+ bool
+
config SIFIVE_U_OTP
bool
diff --git a/hw/misc/meson.build b/hw/misc/meson.build
index a40245ad44..37b4bbf31d 100644
--- a/hw/misc/meson.build
+++ b/hw/misc/meson.build
@@ -30,6 +30,7 @@ softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true: files('sifive_test.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c'))
+softmmu_ss.add(when: 'CONFIG_SIFIVE_E_AON', if_true: files('sifive_e_aon.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
diff --git a/hw/misc/sifive_e_aon.c b/hw/misc/sifive_e_aon.c
new file mode 100644
index 0000000000..b66a9e40fa
--- /dev/null
+++ b/hw/misc/sifive_e_aon.c
@@ -0,0 +1,326 @@
+/*
+ * SiFive HiFive1 AON (Always On Domain) for QEMU.
+ *
+ * Copyright (c) 2022 SiFive, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
+#include "hw/registerfields.h"
+#include "hw/misc/sifive_e_aon.h"
+#include "qapi/visitor.h"
+#include "qapi/error.h"
+#include "sysemu/watchdog.h"
+#include "hw/qdev-properties.h"
+
+REG32(AON_WDT_WDOGCFG, 0x0)
+ FIELD(AON_WDT_WDOGCFG, SCALE, 0, 4)
+ FIELD(AON_WDT_WDOGCFG, RSVD0, 4, 4)
+ FIELD(AON_WDT_WDOGCFG, RSTEN, 8, 1)
+ FIELD(AON_WDT_WDOGCFG, ZEROCMP, 9, 1)
+ FIELD(AON_WDT_WDOGCFG, RSVD1, 10, 2)
+ FIELD(AON_WDT_WDOGCFG, EN_ALWAYS, 12, 1)
+ FIELD(AON_WDT_WDOGCFG, EN_CORE_AWAKE, 13, 1)
+ FIELD(AON_WDT_WDOGCFG, RSVD2, 14, 14)
+ FIELD(AON_WDT_WDOGCFG, IP0, 28, 1)
+ FIELD(AON_WDT_WDOGCFG, RSVD3, 29, 3)
+REG32(AON_WDT_WDOGCOUNT, 0x8)
+REG32(AON_WDT_WDOGS, 0x10)
+REG32(AON_WDT_WDOGFEED, 0x18)
+REG32(AON_WDT_WDOGKEY, 0x1c)
+REG32(AON_WDT_WDOGCMP0, 0x20)
+
+static void sifive_e_aon_wdt_update_wdogcount(SiFiveEAONState *r)
+{
+ int64_t now;
+ if (0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) &&
+ 0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE)) {
+ return;
+ }
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ r->wdogcount += muldiv64(now - r->wdog_restart_time,
+ r->wdogclk_freq, NANOSECONDS_PER_SECOND);
+
+ /* Clean the most significant bit. */
+ r->wdogcount = ((r->wdogcount << 1) >> 1);
+ r->wdog_restart_time = now;
+}
+
+static void sifive_e_aon_wdt_update_state(SiFiveEAONState *r)
+{
+ uint16_t wdogs;
+ bool cmp_signal = false;
+ sifive_e_aon_wdt_update_wdogcount(r);
+ wdogs = (uint16_t)(r->wdogcount >>
+ FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE));
+
+ if (wdogs >= r->wdogcmp0) {
+ cmp_signal = true;
+ if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP)) {
+ r->wdogcount = 0;
+ wdogs = 0;
+ }
+ }
+
+ if (cmp_signal) {
+ if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN)) {
+ watchdog_perform_action();
+ }
+ r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, IP0, 1);
+ }
+
+ qemu_set_irq(r->wdog_irq, FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, IP0));
+
+ if (wdogs < r->wdogcmp0 &&
+ (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) ||
+ FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE))) {
+ int64_t next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ next += muldiv64((r->wdogcmp0 - wdogs) <<
+ FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE),
+ NANOSECONDS_PER_SECOND, r->wdogclk_freq);
+ timer_mod(r->wdog_timer, next);
+ } else {
+ timer_mod(r->wdog_timer, INT64_MAX);
+ }
+}
+
+/*
+ * Callback used when the timer set using timer_mod expires.
+ */
+static void sifive_e_aon_wdt_expired_cb(void *opaque)
+{
+ SiFiveEAONState *r = SIFIVE_E_AON(opaque);
+ sifive_e_aon_wdt_update_state(r);
+}
+
+static uint64_t
+sifive_e_aon_wdt_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ SiFiveEAONState *r = SIFIVE_E_AON(opaque);
+
+ switch (addr) {
+ case A_AON_WDT_WDOGCFG:
+ return r->wdogcfg;
+ case A_AON_WDT_WDOGCOUNT:
+ sifive_e_aon_wdt_update_wdogcount(r);
+ return r->wdogcount;
+ case A_AON_WDT_WDOGS:
+ sifive_e_aon_wdt_update_wdogcount(r);
+ return r->wdogcount >>
+ FIELD_EX32(r->wdogcfg,
+ AON_WDT_WDOGCFG,
+ SCALE);
+ case A_AON_WDT_WDOGFEED:
+ return 0;
+ case A_AON_WDT_WDOGKEY:
+ return r->wdogunlock;
+ case A_AON_WDT_WDOGCMP0:
+ return r->wdogcmp0;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
+ __func__, (int)addr);
+ }
+
+ return 0;
+}
+
+static void
+sifive_e_aon_wdt_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ SiFiveEAONState *r = SIFIVE_E_AON(opaque);
+ uint32_t value = val64;
+
+ switch (addr) {
+ case A_AON_WDT_WDOGCFG: {
+ uint8_t new_en_always;
+ uint8_t new_en_core_awake;
+ uint8_t old_en_always;
+ uint8_t old_en_core_awake;
+ if (0 == r->wdogunlock) {
+ return;
+ }
+
+ new_en_always = FIELD_EX32(value, AON_WDT_WDOGCFG, EN_ALWAYS);
+ new_en_core_awake = FIELD_EX32(value, AON_WDT_WDOGCFG, EN_CORE_AWAKE);
+ old_en_always = FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS);
+ old_en_core_awake = FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG,
+ EN_CORE_AWAKE);
+
+ if (1 == (old_en_always ||
+ old_en_core_awake) &&
+ 0 == (new_en_always ||
+ new_en_core_awake)) {
+ sifive_e_aon_wdt_update_wdogcount(r);
+ } else if (0 == (old_en_always ||
+ old_en_core_awake) &&
+ 1 == (new_en_always ||
+ new_en_core_awake)) {
+ r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ }
+ r->wdogcfg = value;
+ r->wdogunlock = 0;
+ break;
+ }
+ case A_AON_WDT_WDOGCOUNT:
+ if (0 == r->wdogunlock) {
+ return;
+ }
+ r->wdogcount = ((value << 1) >> 1);
+ r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ r->wdogunlock = 0;
+ break;
+ case A_AON_WDT_WDOGS:
+ return;
+ case A_AON_WDT_WDOGFEED:
+ if (0 == r->wdogunlock) {
+ return;
+ }
+ if (SIFIVE_E_AON_WDOGFEED == value) {
+ r->wdogcount = 0;
+ r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ }
+ r->wdogunlock = 0;
+ break;
+ case A_AON_WDT_WDOGKEY:
+ if (SIFIVE_E_AON_WDOGKEY == value) {
+ r->wdogunlock = 1;
+ }
+ break;
+ case A_AON_WDT_WDOGCMP0:
+ if (0 == r->wdogunlock) {
+ return;
+ }
+ r->wdogcmp0 = (uint16_t) value;
+ r->wdogunlock = 0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n",
+ __func__, (int)addr, (int)value);
+ }
+ sifive_e_aon_wdt_update_state(r);
+}
+
+static uint64_t
+sifive_e_aon_read(void *opaque, hwaddr addr, unsigned int size)
+{
+ if (addr < SIFIVE_E_AON_RTC) {
+ return sifive_e_aon_wdt_read(opaque, addr, size);
+ } else if (addr < SIFIVE_E_AON_MAX) {
+ qemu_log_mask(LOG_UNIMP, "%s: Unimplemented read: addr=0x%x\n",
+ __func__, (int)addr);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n",
+ __func__, (int)addr);
+ }
+ return 0;
+}
+
+static void
+sifive_e_aon_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ if (addr < SIFIVE_E_AON_RTC) {
+ sifive_e_aon_wdt_write(opaque, addr, val64, size);
+ } else if (addr < SIFIVE_E_AON_MAX) {
+ qemu_log_mask(LOG_UNIMP, "%s: Unimplemented write: addr=0x%x\n",
+ __func__, (int)addr);
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x\n",
+ __func__, (int)addr);
+ }
+}
+
+static const MemoryRegionOps sifive_e_aon_ops = {
+ .read = sifive_e_aon_read,
+ .write = sifive_e_aon_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ },
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4
+ }
+};
+
+static void sifive_e_aon_reset(DeviceState *dev)
+{
+ SiFiveEAONState *r = SIFIVE_E_AON(dev);
+
+ r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN, 0);
+ r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS, 0);
+ r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE, 0);
+ r->wdogcmp0 = 0xbeef;
+
+ sifive_e_aon_wdt_update_state(r);
+}
+
+static void sifive_e_aon_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ SiFiveEAONState *r = SIFIVE_E_AON(obj);
+
+ memory_region_init_io(&r->mmio, OBJECT(r), &sifive_e_aon_ops, r,
+ TYPE_SIFIVE_E_AON, SIFIVE_E_AON_MAX);
+ sysbus_init_mmio(sbd, &r->mmio);
+
+ /* watchdog timer */
+ r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
+ sysbus_init_irq(sbd, &r->wdog_irq);
+}
+
+static void sifive_e_aon_realize(DeviceState *dev, Error **errp)
+{
+ SiFiveEAONState *r = SIFIVE_E_AON(dev);
+
+ /* watchdog timer */
+ r->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+ sifive_e_aon_wdt_expired_cb, r);
+}
+
+static Property sifive_e_aon_properties[] = {
+ DEFINE_PROP_UINT64("wdogclk-frequency", SiFiveEAONState, wdogclk_freq,
+ SIFIVE_E_LFCLK_DEFAULT_FREQ),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sifive_e_aon_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = sifive_e_aon_realize;
+ dc->reset = sifive_e_aon_reset;
+ device_class_set_props(dc, sifive_e_aon_properties);
+}
+
+static const TypeInfo sifive_e_aon_info = {
+ .name = TYPE_SIFIVE_E_AON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SiFiveEAONState),
+ .instance_init = sifive_e_aon_init,
+ .class_init = sifive_e_aon_class_init,
+};
+
+static void sifive_e_aon_register_types(void)
+{
+ type_register_static(&sifive_e_aon_info);
+}
+
+type_init(sifive_e_aon_register_types)
diff --git a/include/hw/misc/sifive_e_aon.h b/include/hw/misc/sifive_e_aon.h
new file mode 100644
index 0000000000..2ae1c4139c
--- /dev/null
+++ b/include/hw/misc/sifive_e_aon.h
@@ -0,0 +1,60 @@
+/*
+ * SiFive HiFive1 AON (Always On Domain) interface.
+ *
+ * Copyright (c) 2022 SiFive, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SIFIVE_AON_H
+#define HW_SIFIVE_AON_H
+
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_SIFIVE_E_AON "riscv.sifive.e.aon"
+OBJECT_DECLARE_SIMPLE_TYPE(SiFiveEAONState, SIFIVE_E_AON)
+
+#define SIFIVE_E_AON_WDOGKEY (0x51F15E)
+#define SIFIVE_E_AON_WDOGFEED (0xD09F00D)
+#define SIFIVE_E_LFCLK_DEFAULT_FREQ (32768)
+
+enum {
+ SIFIVE_E_AON_WDT = 0x0,
+ SIFIVE_E_AON_RTC = 0x40,
+ SIFIVE_E_AON_LFROSC = 0x70,
+ SIFIVE_E_AON_BACKUP = 0x80,
+ SIFIVE_E_AON_PMU = 0x100,
+ SIFIVE_E_AON_MAX = 0x150
+};
+
+struct SiFiveEAONState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ MemoryRegion mmio;
+
+ /*< watchdog timer >*/
+ QEMUTimer *wdog_timer;
+ qemu_irq wdog_irq;
+ uint64_t wdog_restart_time;
+ uint64_t wdogclk_freq;
+
+ uint32_t wdogcfg;
+ uint16_t wdogcmp0;
+ uint32_t wdogcount;
+ uint8_t wdogunlock;
+};
+
+#endif
--
2.27.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/3] hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
2023-05-23 8:49 [PATCH v4 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
2023-05-23 8:49 ` [PATCH v4 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
@ 2023-05-23 8:49 ` Tommy Wu
2023-05-25 2:42 ` Alistair Francis
2023-05-25 12:06 ` Philippe Mathieu-Daudé
2023-05-23 8:49 ` [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
2 siblings, 2 replies; 9+ messages in thread
From: Tommy Wu @ 2023-05-23 8:49 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei, Tommy Wu
Create the AON device when we realize the sifive_e machine.
This patch only implemented the functionality of the watchdog timer,
not all the functionality of the AON device.
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
---
hw/riscv/Kconfig | 1 +
hw/riscv/sifive_e.c | 13 +++++++++++--
include/hw/riscv/sifive_e.h | 8 +++++---
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
index 6528ebfa3a..b6a5eb4452 100644
--- a/hw/riscv/Kconfig
+++ b/hw/riscv/Kconfig
@@ -60,6 +60,7 @@ config SIFIVE_E
select SIFIVE_PLIC
select SIFIVE_UART
select SIFIVE_E_PRCI
+ select SIFIVE_E_AON
select UNIMP
config SIFIVE_U
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
index 04939b60c3..731ed0e11d 100644
--- a/hw/riscv/sifive_e.c
+++ b/hw/riscv/sifive_e.c
@@ -45,6 +45,7 @@
#include "hw/intc/riscv_aclint.h"
#include "hw/intc/sifive_plic.h"
#include "hw/misc/sifive_e_prci.h"
+#include "hw/misc/sifive_e_aon.h"
#include "chardev/char.h"
#include "sysemu/sysemu.h"
@@ -223,8 +224,13 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
- create_unimplemented_device("riscv.sifive.e.aon",
- memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
+
+ s->aon = qdev_new(TYPE_SIFIVE_E_AON);
+ if (!sysbus_realize(SYS_BUS_DEVICE(s->aon), errp)) {
+ return;
+ }
+ sysbus_mmio_map(SYS_BUS_DEVICE(s->aon), 0, memmap[SIFIVE_E_DEV_AON].base);
+
sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
/* GPIO */
@@ -245,6 +251,9 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(s->plic),
SIFIVE_E_GPIO0_IRQ0 + i));
}
+ sysbus_connect_irq(SYS_BUS_DEVICE(s->aon), 0,
+ qdev_get_gpio_in(DEVICE(s->plic),
+ SIFIVE_E_AON_WDT_IRQ));
sifive_uart_create(sys_mem, memmap[SIFIVE_E_DEV_UART0].base,
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ));
diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h
index b824a79e2d..a094b47e0b 100644
--- a/include/hw/riscv/sifive_e.h
+++ b/include/hw/riscv/sifive_e.h
@@ -35,6 +35,7 @@ typedef struct SiFiveESoCState {
/*< public >*/
RISCVHartArrayState cpus;
DeviceState *plic;
+ DeviceState *aon;
SIFIVEGPIOState gpio;
MemoryRegion xip_mem;
MemoryRegion mask_rom;
@@ -76,9 +77,10 @@ enum {
};
enum {
- SIFIVE_E_UART0_IRQ = 3,
- SIFIVE_E_UART1_IRQ = 4,
- SIFIVE_E_GPIO0_IRQ0 = 8
+ SIFIVE_E_AON_WDT_IRQ = 1,
+ SIFIVE_E_UART0_IRQ = 3,
+ SIFIVE_E_UART1_IRQ = 4,
+ SIFIVE_E_GPIO0_IRQ0 = 8
};
#define SIFIVE_E_PLIC_HART_CONFIG "M"
--
2.27.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e
2023-05-23 8:49 [PATCH v4 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
2023-05-23 8:49 ` [PATCH v4 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
2023-05-23 8:49 ` [PATCH v4 2/3] hw/riscv: sifive_e: " Tommy Wu
@ 2023-05-23 8:49 ` Tommy Wu
2023-05-25 7:25 ` Thomas Huth
2 siblings, 1 reply; 9+ messages in thread
From: Tommy Wu @ 2023-05-23 8:49 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei, Tommy Wu
Add some simple tests of the watchdog timer in the always-on domain device
of HiFive 1 rev b.
Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
---
tests/qtest/meson.build | 3 +
tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
2 files changed, 453 insertions(+)
create mode 100644 tests/qtest/sifive-e-aon-watchdog-test.c
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 4c5585ac0f..963f93e298 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -231,6 +231,9 @@ qtests_s390x = \
'cpu-plug-test',
'migration-test']
+qtests_riscv32 = \
+ (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? ['sifive-e-aon-watchdog-test'] : [])
+
qos_test_ss = ss.source_set()
qos_test_ss.add(
'ac97-test.c',
diff --git a/tests/qtest/sifive-e-aon-watchdog-test.c b/tests/qtest/sifive-e-aon-watchdog-test.c
new file mode 100644
index 0000000000..1f313d16ad
--- /dev/null
+++ b/tests/qtest/sifive-e-aon-watchdog-test.c
@@ -0,0 +1,450 @@
+/*
+ * QTest testcase for the watchdog timer of HiFive 1 rev b.
+ *
+ * Copyright (c) 2023 SiFive, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "qemu/bitops.h"
+#include "libqtest.h"
+#include "hw/registerfields.h"
+#include "hw/misc/sifive_e_aon.h"
+
+FIELD(AON_WDT_WDOGCFG, SCALE, 0, 4)
+FIELD(AON_WDT_WDOGCFG, RSVD0, 4, 4)
+FIELD(AON_WDT_WDOGCFG, RSTEN, 8, 1)
+FIELD(AON_WDT_WDOGCFG, ZEROCMP, 9, 1)
+FIELD(AON_WDT_WDOGCFG, RSVD1, 10, 2)
+FIELD(AON_WDT_WDOGCFG, EN_ALWAYS, 12, 1)
+FIELD(AON_WDT_WDOGCFG, EN_CORE_AWAKE, 13, 1)
+FIELD(AON_WDT_WDOGCFG, RSVD2, 14, 14)
+FIELD(AON_WDT_WDOGCFG, IP0, 28, 1)
+FIELD(AON_WDT_WDOGCFG, RSVD3, 29, 3)
+
+#define WDOG_BASE (0x10000000)
+#define WDOGCFG (0x0)
+#define WDOGCOUNT (0x8)
+#define WDOGS (0x10)
+#define WDOGFEED (0x18)
+#define WDOGKEY (0x1c)
+#define WDOGCMP0 (0x20)
+
+#define SIFIVE_E_AON_WDOGKEY (0x51F15E)
+#define SIFIVE_E_AON_WDOGFEED (0xD09F00D)
+#define SIFIVE_E_LFCLK_DEFAULT_FREQ (32768)
+
+static void test_init(QTestState *qts)
+{
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, 0);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, 0xBEEF);
+}
+
+static void test_wdogcount(void)
+{
+ uint64_t tmp;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ tmp = qtest_readl(qts, WDOG_BASE + WDOGCOUNT);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0xBEEF);
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) == tmp);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0xBEEF);
+ g_assert(0xBEEF == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0xAAAAAAAA);
+ g_assert(0x2AAAAAAA == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGFEED, 0xAAAAAAAA);
+ g_assert(0x2AAAAAAA == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGFEED, SIFIVE_E_AON_WDOGFEED);
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+
+ qtest_quit(qts);
+}
+
+static void test_wdogcfg(void)
+{
+ uint32_t tmp_cfg;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ tmp_cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, 0xFFFFFFFF);
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCFG) == tmp_cfg);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, 0xFFFFFFFF);
+ g_assert(0xFFFFFFFF == qtest_readl(qts, WDOG_BASE + WDOGCFG));
+
+ tmp_cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(15 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(1 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(1 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(1 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, 0);
+ tmp_cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(0 == FIELD_EX32(tmp_cfg, AON_WDT_WDOGCFG, IP0));
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGCFG));
+
+ qtest_quit(qts);
+}
+
+static void test_wdogcmp0(void)
+{
+ uint32_t tmp;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ tmp = qtest_readl(qts, WDOG_BASE + WDOGCMP0);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, 0xBEEF);
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCMP0) == tmp);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, 0xBEEF);
+ g_assert(0xBEEF == qtest_readl(qts, WDOG_BASE + WDOGCMP0));
+
+ qtest_quit(qts);
+}
+
+static void test_wdogkey(void)
+{
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGKEY));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, 0xFFFF);
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGKEY));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ g_assert(1 == qtest_readl(qts, WDOG_BASE + WDOGKEY));
+
+ qtest_writel(qts, WDOG_BASE + WDOGFEED, 0xAAAAAAAA);
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGKEY));
+
+ qtest_quit(qts);
+}
+
+static void test_wdogfeed(void)
+{
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGFEED));
+
+ qtest_writel(qts, WDOG_BASE + WDOGFEED, 0xFFFF);
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGFEED));
+
+ qtest_quit(qts);
+}
+
+static void test_scaled_wdogs(void)
+{
+ uint32_t cfg;
+ uint32_t fake_count = 0x12345678;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, fake_count);
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) == fake_count);
+ g_assert((uint16_t)qtest_readl(qts, WDOG_BASE + WDOGS) ==
+ (uint16_t)fake_count);
+
+ for (int i = 0; i < 16; i++) {
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, SCALE, i);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ g_assert((uint16_t)qtest_readl(qts, WDOG_BASE + WDOGS) ==
+ (uint16_t)(fake_count >>
+ FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE)));
+ }
+
+ qtest_quit(qts);
+}
+
+static void test_watchdog(void)
+{
+ uint32_t cfg;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, SIFIVE_E_LFCLK_DEFAULT_FREQ);
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, SCALE, 0);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 1);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND);
+
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ);
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGS) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ);
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, IP0, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_quit(qts);
+}
+
+static void test_scaled_watchdog(void)
+{
+ uint32_t cfg;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, 10);
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, SCALE, 15);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 1);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 10);
+
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ * 10);
+
+ g_assert(10 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(15 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, IP0, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_quit(qts);
+}
+
+static void test_periodic_int(void)
+{
+ uint32_t cfg;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, SIFIVE_E_LFCLK_DEFAULT_FREQ);
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, SCALE, 0);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, ZEROCMP, 1);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 1);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND);
+
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, IP0, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND);
+
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGCOUNT));
+ g_assert(0 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, IP0, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_quit(qts);
+}
+
+static void test_enable_disable(void)
+{
+ uint32_t cfg;
+ QTestState *qts = qtest_init("-machine sifive_e");
+
+ test_init(qts);
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCMP0, 10);
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, SCALE, 15);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 1);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 2);
+
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ * 2);
+ g_assert(2 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(15 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 8);
+
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ * 2);
+ g_assert(2 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(15 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS, 1);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+
+ qtest_clock_step(qts, NANOSECONDS_PER_SECOND * 8);
+
+ g_assert(qtest_readl(qts, WDOG_BASE + WDOGCOUNT) ==
+ SIFIVE_E_LFCLK_DEFAULT_FREQ * 10);
+ g_assert(10 == qtest_readl(qts, WDOG_BASE + WDOGS));
+
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(15 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, SCALE));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, RSTEN));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, ZEROCMP));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_ALWAYS));
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE));
+ g_assert(1 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCOUNT, 0);
+ cfg = FIELD_DP32(cfg, AON_WDT_WDOGCFG, IP0, 0);
+ qtest_writel(qts, WDOG_BASE + WDOGKEY, SIFIVE_E_AON_WDOGKEY);
+ qtest_writel(qts, WDOG_BASE + WDOGCFG, cfg);
+ cfg = qtest_readl(qts, WDOG_BASE + WDOGCFG);
+ g_assert(0 == FIELD_EX32(cfg, AON_WDT_WDOGCFG, IP0));
+
+ qtest_quit(qts);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/sifive-e-aon-watchdog-test/wdogcount",
+ test_wdogcount);
+ qtest_add_func("/sifive-e-aon-watchdog-test/wdogcfg",
+ test_wdogcfg);
+ qtest_add_func("/sifive-e-aon-watchdog-test/wdogcmp0",
+ test_wdogcmp0);
+ qtest_add_func("/sifive-e-aon-watchdog-test/wdogkey",
+ test_wdogkey);
+ qtest_add_func("/sifive-e-aon-watchdog-test/wdogfeed",
+ test_wdogfeed);
+ qtest_add_func("/sifive-e-aon-watchdog-test/scaled_wdogs",
+ test_scaled_wdogs);
+ qtest_add_func("/sifive-e-aon-watchdog-test/watchdog",
+ test_watchdog);
+ qtest_add_func("/sifive-e-aon-watchdog-test/scaled_watchdog",
+ test_scaled_watchdog);
+ qtest_add_func("/sifive-e-aon-watchdog-test/periodic_int",
+ test_periodic_int);
+ qtest_add_func("/sifive-e-aon-watchdog-test/enable_disable",
+ test_enable_disable);
+ return g_test_run();
+}
--
2.27.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
2023-05-23 8:49 ` [PATCH v4 2/3] hw/riscv: sifive_e: " Tommy Wu
@ 2023-05-25 2:42 ` Alistair Francis
2023-05-25 12:06 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2023-05-25 2:42 UTC (permalink / raw)
To: Tommy Wu
Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
jim.shu, frank.chang, thuth, liweiwei
On Tue, May 23, 2023 at 6:50 PM Tommy Wu <tommy.wu@sifive.com> wrote:
>
> Create the AON device when we realize the sifive_e machine.
> This patch only implemented the functionality of the watchdog timer,
> not all the functionality of the AON device.
>
> Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/riscv/Kconfig | 1 +
> hw/riscv/sifive_e.c | 13 +++++++++++--
> include/hw/riscv/sifive_e.h | 8 +++++---
> 3 files changed, 17 insertions(+), 5 deletions(-)
>
> diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig
> index 6528ebfa3a..b6a5eb4452 100644
> --- a/hw/riscv/Kconfig
> +++ b/hw/riscv/Kconfig
> @@ -60,6 +60,7 @@ config SIFIVE_E
> select SIFIVE_PLIC
> select SIFIVE_UART
> select SIFIVE_E_PRCI
> + select SIFIVE_E_AON
> select UNIMP
>
> config SIFIVE_U
> diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c
> index 04939b60c3..731ed0e11d 100644
> --- a/hw/riscv/sifive_e.c
> +++ b/hw/riscv/sifive_e.c
> @@ -45,6 +45,7 @@
> #include "hw/intc/riscv_aclint.h"
> #include "hw/intc/sifive_plic.h"
> #include "hw/misc/sifive_e_prci.h"
> +#include "hw/misc/sifive_e_aon.h"
> #include "chardev/char.h"
> #include "sysemu/sysemu.h"
>
> @@ -223,8 +224,13 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
> RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
> RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
> - create_unimplemented_device("riscv.sifive.e.aon",
> - memmap[SIFIVE_E_DEV_AON].base, memmap[SIFIVE_E_DEV_AON].size);
> +
> + s->aon = qdev_new(TYPE_SIFIVE_E_AON);
> + if (!sysbus_realize(SYS_BUS_DEVICE(s->aon), errp)) {
> + return;
> + }
> + sysbus_mmio_map(SYS_BUS_DEVICE(s->aon), 0, memmap[SIFIVE_E_DEV_AON].base);
> +
> sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
>
> /* GPIO */
> @@ -245,6 +251,9 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> qdev_get_gpio_in(DEVICE(s->plic),
> SIFIVE_E_GPIO0_IRQ0 + i));
> }
> + sysbus_connect_irq(SYS_BUS_DEVICE(s->aon), 0,
> + qdev_get_gpio_in(DEVICE(s->plic),
> + SIFIVE_E_AON_WDT_IRQ));
>
> sifive_uart_create(sys_mem, memmap[SIFIVE_E_DEV_UART0].base,
> serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ));
> diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h
> index b824a79e2d..a094b47e0b 100644
> --- a/include/hw/riscv/sifive_e.h
> +++ b/include/hw/riscv/sifive_e.h
> @@ -35,6 +35,7 @@ typedef struct SiFiveESoCState {
> /*< public >*/
> RISCVHartArrayState cpus;
> DeviceState *plic;
> + DeviceState *aon;
> SIFIVEGPIOState gpio;
> MemoryRegion xip_mem;
> MemoryRegion mask_rom;
> @@ -76,9 +77,10 @@ enum {
> };
>
> enum {
> - SIFIVE_E_UART0_IRQ = 3,
> - SIFIVE_E_UART1_IRQ = 4,
> - SIFIVE_E_GPIO0_IRQ0 = 8
> + SIFIVE_E_AON_WDT_IRQ = 1,
> + SIFIVE_E_UART0_IRQ = 3,
> + SIFIVE_E_UART1_IRQ = 4,
> + SIFIVE_E_GPIO0_IRQ0 = 8
> };
>
> #define SIFIVE_E_PLIC_HART_CONFIG "M"
> --
> 2.27.0
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e
2023-05-23 8:49 ` [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
@ 2023-05-25 7:25 ` Thomas Huth
0 siblings, 0 replies; 9+ messages in thread
From: Thomas Huth @ 2023-05-25 7:25 UTC (permalink / raw)
To: Tommy Wu, qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, liweiwei
On 23/05/2023 10.49, Tommy Wu wrote:
> Add some simple tests of the watchdog timer in the always-on domain device
> of HiFive 1 rev b.
>
> Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
> ---
> tests/qtest/meson.build | 3 +
> tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
> 2 files changed, 453 insertions(+)
> create mode 100644 tests/qtest/sifive-e-aon-watchdog-test.c
Acked-by: Thomas Huth <thuth@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
2023-05-23 8:49 ` [PATCH v4 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
@ 2023-05-25 12:05 ` Philippe Mathieu-Daudé
2023-06-08 16:56 ` Tommy Wu
0 siblings, 1 reply; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-05-25 12:05 UTC (permalink / raw)
To: Tommy Wu, qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei
Hi Tommy,
On 23/5/23 10:49, Tommy Wu wrote:
> The watchdog timer is in the always-on domain device of HiFive 1 rev b,
> so this patch added the AON device to the sifive_e machine. This patch
> only implemented the functionality of the watchdog timer.
>
> Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
> ---
> hw/misc/Kconfig | 3 +
> hw/misc/meson.build | 1 +
> hw/misc/sifive_e_aon.c | 326 +++++++++++++++++++++++++++++++++
> include/hw/misc/sifive_e_aon.h | 60 ++++++
> 4 files changed, 390 insertions(+)
> create mode 100644 hw/misc/sifive_e_aon.c
> create mode 100644 include/hw/misc/sifive_e_aon.h
> +REG32(AON_WDT_WDOGCFG, 0x0)
> + FIELD(AON_WDT_WDOGCFG, SCALE, 0, 4)
> + FIELD(AON_WDT_WDOGCFG, RSVD0, 4, 4)
> + FIELD(AON_WDT_WDOGCFG, RSTEN, 8, 1)
> + FIELD(AON_WDT_WDOGCFG, ZEROCMP, 9, 1)
> + FIELD(AON_WDT_WDOGCFG, RSVD1, 10, 2)
> + FIELD(AON_WDT_WDOGCFG, EN_ALWAYS, 12, 1)
> + FIELD(AON_WDT_WDOGCFG, EN_CORE_AWAKE, 13, 1)
> + FIELD(AON_WDT_WDOGCFG, RSVD2, 14, 14)
> + FIELD(AON_WDT_WDOGCFG, IP0, 28, 1)
> + FIELD(AON_WDT_WDOGCFG, RSVD3, 29, 3)
> +REG32(AON_WDT_WDOGCOUNT, 0x8)
Adding:
FIELD(AON_WDT_WDOGCOUNT, VALUE, 0, 31)
...
> +REG32(AON_WDT_WDOGS, 0x10)
> +REG32(AON_WDT_WDOGFEED, 0x18)
> +REG32(AON_WDT_WDOGKEY, 0x1c)
> +REG32(AON_WDT_WDOGCMP0, 0x20)
> +
> +static void sifive_e_aon_wdt_update_wdogcount(SiFiveEAONState *r)
> +{
> + int64_t now;
> + if (0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) &&
> + 0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE)) {
> + return;
> + }
> +
> + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> + r->wdogcount += muldiv64(now - r->wdog_restart_time,
> + r->wdogclk_freq, NANOSECONDS_PER_SECOND);
> +
> + /* Clean the most significant bit. */
> + r->wdogcount = ((r->wdogcount << 1) >> 1);
... you could use:
r->wdogcount &= R_AON_WDT_WDOGCOUNT_VALUE_MASK
> + r->wdog_restart_time = now;
> +}
> +
> +static void sifive_e_aon_wdt_update_state(SiFiveEAONState *r)
> +{
> + uint16_t wdogs;
> + bool cmp_signal = false;
> + sifive_e_aon_wdt_update_wdogcount(r);
> + wdogs = (uint16_t)(r->wdogcount >>
> + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE));
> +
> + if (wdogs >= r->wdogcmp0) {
> + cmp_signal = true;
> + if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP)) {
> + r->wdogcount = 0;
> + wdogs = 0;
> + }
> + }
> +
> + if (cmp_signal) {
> + if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN)) {
You sometimes check bit equality, ...
> + watchdog_perform_action();
> + }
> + r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, IP0, 1);
> + }
> +
> + qemu_set_irq(r->wdog_irq, FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, IP0));
> +
> + if (wdogs < r->wdogcmp0 &&
> + (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) ||
... sometimes you don't. Code style consistency would be better.
(Also, most of QEMU code base check equality using constant value
on the right side of the comparaison).
> + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE))) {
> + int64_t next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> + next += muldiv64((r->wdogcmp0 - wdogs) <<
> + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE),
> + NANOSECONDS_PER_SECOND, r->wdogclk_freq);
> + timer_mod(r->wdog_timer, next);
> + } else {
> + timer_mod(r->wdog_timer, INT64_MAX);
> + }
> +}
> +static void sifive_e_aon_init(Object *obj)
> +{
> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> + SiFiveEAONState *r = SIFIVE_E_AON(obj);
> +
> + memory_region_init_io(&r->mmio, OBJECT(r), &sifive_e_aon_ops, r,
> + TYPE_SIFIVE_E_AON, SIFIVE_E_AON_MAX);
> + sysbus_init_mmio(sbd, &r->mmio);
> +
> + /* watchdog timer */
> + r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
> + sysbus_init_irq(sbd, &r->wdog_irq);
> +}
> +
> +static void sifive_e_aon_realize(DeviceState *dev, Error **errp)
> +{
> + SiFiveEAONState *r = SIFIVE_E_AON(dev);
> +
> + /* watchdog timer */
> + r->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> + sifive_e_aon_wdt_expired_cb, r);
You should be able to create the timer in sifive_e_aon_init().
> +}
Regards,
Phil.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/3] hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
2023-05-23 8:49 ` [PATCH v4 2/3] hw/riscv: sifive_e: " Tommy Wu
2023-05-25 2:42 ` Alistair Francis
@ 2023-05-25 12:06 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 9+ messages in thread
From: Philippe Mathieu-Daudé @ 2023-05-25 12:06 UTC (permalink / raw)
To: Tommy Wu, qemu-devel, qemu-riscv
Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang, thuth,
liweiwei
On 23/5/23 10:49, Tommy Wu wrote:
> Create the AON device when we realize the sifive_e machine.
> This patch only implemented the functionality of the watchdog timer,
> not all the functionality of the AON device.
>
> Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> Reviewed-by: Frank Chang <frank.chang@sifive.com>
> ---
> hw/riscv/Kconfig | 1 +
> hw/riscv/sifive_e.c | 13 +++++++++++--
> include/hw/riscv/sifive_e.h | 8 +++++---
> 3 files changed, 17 insertions(+), 5 deletions(-)
> diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h
> index b824a79e2d..a094b47e0b 100644
> --- a/include/hw/riscv/sifive_e.h
> +++ b/include/hw/riscv/sifive_e.h
> @@ -35,6 +35,7 @@ typedef struct SiFiveESoCState {
> /*< public >*/
> RISCVHartArrayState cpus;
> DeviceState *plic;
> + DeviceState *aon;
Preferably allocate the device state in the SoC, similar to gpio:
SiFiveEAONState aon;
> SIFIVEGPIOState gpio;
> MemoryRegion xip_mem;
> MemoryRegion mask_rom;
> @@ -76,9 +77,10 @@ enum {
> };
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/3] hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
2023-05-25 12:05 ` Philippe Mathieu-Daudé
@ 2023-06-08 16:56 ` Tommy Wu
0 siblings, 0 replies; 9+ messages in thread
From: Tommy Wu @ 2023-06-08 16:56 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
jim.shu, frank.chang, thuth, liweiwei
[-- Attachment #1: Type: text/plain, Size: 5144 bytes --]
Hi Phil,
Thanks for all the suggestions, I'll send patch v5 to fix all the issues.
Best Regards,
Tommy
On Thu, May 25, 2023 at 8:05 PM Philippe Mathieu-Daudé <philmd@linaro.org>
wrote:
> Hi Tommy,
>
> On 23/5/23 10:49, Tommy Wu wrote:
> > The watchdog timer is in the always-on domain device of HiFive 1 rev b,
> > so this patch added the AON device to the sifive_e machine. This patch
> > only implemented the functionality of the watchdog timer.
> >
> > Signed-off-by: Tommy Wu <tommy.wu@sifive.com>
> > Reviewed-by: Frank Chang <frank.chang@sifive.com>
> > ---
> > hw/misc/Kconfig | 3 +
> > hw/misc/meson.build | 1 +
> > hw/misc/sifive_e_aon.c | 326 +++++++++++++++++++++++++++++++++
> > include/hw/misc/sifive_e_aon.h | 60 ++++++
> > 4 files changed, 390 insertions(+)
> > create mode 100644 hw/misc/sifive_e_aon.c
> > create mode 100644 include/hw/misc/sifive_e_aon.h
>
>
> > +REG32(AON_WDT_WDOGCFG, 0x0)
> > + FIELD(AON_WDT_WDOGCFG, SCALE, 0, 4)
> > + FIELD(AON_WDT_WDOGCFG, RSVD0, 4, 4)
> > + FIELD(AON_WDT_WDOGCFG, RSTEN, 8, 1)
> > + FIELD(AON_WDT_WDOGCFG, ZEROCMP, 9, 1)
> > + FIELD(AON_WDT_WDOGCFG, RSVD1, 10, 2)
> > + FIELD(AON_WDT_WDOGCFG, EN_ALWAYS, 12, 1)
> > + FIELD(AON_WDT_WDOGCFG, EN_CORE_AWAKE, 13, 1)
> > + FIELD(AON_WDT_WDOGCFG, RSVD2, 14, 14)
> > + FIELD(AON_WDT_WDOGCFG, IP0, 28, 1)
> > + FIELD(AON_WDT_WDOGCFG, RSVD3, 29, 3)
> > +REG32(AON_WDT_WDOGCOUNT, 0x8)
>
> Adding:
>
> FIELD(AON_WDT_WDOGCOUNT, VALUE, 0, 31)
>
> ...
>
> > +REG32(AON_WDT_WDOGS, 0x10)
> > +REG32(AON_WDT_WDOGFEED, 0x18)
> > +REG32(AON_WDT_WDOGKEY, 0x1c)
> > +REG32(AON_WDT_WDOGCMP0, 0x20)
> > +
> > +static void sifive_e_aon_wdt_update_wdogcount(SiFiveEAONState *r)
> > +{
> > + int64_t now;
> > + if (0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) &&
> > + 0 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE)) {
> > + return;
> > + }
> > +
> > + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> > + r->wdogcount += muldiv64(now - r->wdog_restart_time,
> > + r->wdogclk_freq, NANOSECONDS_PER_SECOND);
> > +
> > + /* Clean the most significant bit. */
> > + r->wdogcount = ((r->wdogcount << 1) >> 1);
>
> ... you could use:
>
> r->wdogcount &= R_AON_WDT_WDOGCOUNT_VALUE_MASK
>
> > + r->wdog_restart_time = now;
> > +}
> > +
> > +static void sifive_e_aon_wdt_update_state(SiFiveEAONState *r)
> > +{
> > + uint16_t wdogs;
> > + bool cmp_signal = false;
> > + sifive_e_aon_wdt_update_wdogcount(r);
> > + wdogs = (uint16_t)(r->wdogcount >>
> > + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG,
> SCALE));
> > +
> > + if (wdogs >= r->wdogcmp0) {
> > + cmp_signal = true;
> > + if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP)) {
> > + r->wdogcount = 0;
> > + wdogs = 0;
> > + }
> > + }
> > +
> > + if (cmp_signal) {
> > + if (1 == FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN)) {
>
> You sometimes check bit equality, ...
>
> > + watchdog_perform_action();
> > + }
> > + r->wdogcfg = FIELD_DP32(r->wdogcfg, AON_WDT_WDOGCFG, IP0, 1);
> > + }
> > +
> > + qemu_set_irq(r->wdog_irq, FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG,
> IP0));
> > +
> > + if (wdogs < r->wdogcmp0 &&
> > + (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) ||
>
> ... sometimes you don't. Code style consistency would be better.
>
> (Also, most of QEMU code base check equality using constant value
> on the right side of the comparaison).
>
> > + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE))) {
> > + int64_t next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> > + next += muldiv64((r->wdogcmp0 - wdogs) <<
> > + FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, SCALE),
> > + NANOSECONDS_PER_SECOND, r->wdogclk_freq);
> > + timer_mod(r->wdog_timer, next);
> > + } else {
> > + timer_mod(r->wdog_timer, INT64_MAX);
> > + }
> > +}
>
> > +static void sifive_e_aon_init(Object *obj)
> > +{
> > + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> > + SiFiveEAONState *r = SIFIVE_E_AON(obj);
> > +
> > + memory_region_init_io(&r->mmio, OBJECT(r), &sifive_e_aon_ops, r,
> > + TYPE_SIFIVE_E_AON, SIFIVE_E_AON_MAX);
> > + sysbus_init_mmio(sbd, &r->mmio);
> > +
> > + /* watchdog timer */
> > + r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
> > + sysbus_init_irq(sbd, &r->wdog_irq);
> > +}
> > +
> > +static void sifive_e_aon_realize(DeviceState *dev, Error **errp)
> > +{
> > + SiFiveEAONState *r = SIFIVE_E_AON(dev);
> > +
> > + /* watchdog timer */
> > + r->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> > + sifive_e_aon_wdt_expired_cb, r);
>
> You should be able to create the timer in sifive_e_aon_init().
>
> > +}
>
> Regards,
>
> Phil.
>
[-- Attachment #2: Type: text/html, Size: 6656 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2023-06-08 16:56 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-23 8:49 [PATCH v4 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
2023-05-23 8:49 ` [PATCH v4 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
2023-05-25 12:05 ` Philippe Mathieu-Daudé
2023-06-08 16:56 ` Tommy Wu
2023-05-23 8:49 ` [PATCH v4 2/3] hw/riscv: sifive_e: " Tommy Wu
2023-05-25 2:42 ` Alistair Francis
2023-05-25 12:06 ` Philippe Mathieu-Daudé
2023-05-23 8:49 ` [PATCH v4 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
2023-05-25 7:25 ` Thomas Huth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).