All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b.
@ 2023-06-08 16:45 Tommy Wu
  2023-06-08 16:45 ` [PATCH v5 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Tommy Wu @ 2023-06-08 16:45 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang,
	liweiwei, philmd, 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.

Changes since v4 ( Thank Phil for the feedback ):
- Improve code style consistency.
- Move the timer create function to the sifive_e_aon_init.
- Allocate the sifive_e_aon device state in the SoC.

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                   | 319 ++++++++++++++++
 hw/riscv/Kconfig                         |   1 +
 hw/riscv/sifive_e.c                      |  17 +-
 include/hw/misc/sifive_e_aon.h           |  60 +++
 include/hw/riscv/sifive_e.h              |   9 +-
 tests/qtest/meson.build                  |   3 +
 tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
 9 files changed, 858 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 v5 1/3] hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
  2023-06-08 16:45 [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
@ 2023-06-08 16:45 ` Tommy Wu
  2023-06-22  2:04   ` Alistair Francis
  2023-06-08 16:45 ` [PATCH v5 2/3] hw/riscv: sifive_e: " Tommy Wu
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Tommy Wu @ 2023-06-08 16:45 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang,
	liweiwei, philmd, 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         | 319 +++++++++++++++++++++++++++++++++
 include/hw/misc/sifive_e_aon.h |  60 +++++++
 4 files changed, 383 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 e4c2149175..6996d265e4 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 78ca857c9d..6ac62e6751 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..4656457d0b
--- /dev/null
+++ b/hw/misc/sifive_e_aon.c
@@ -0,0 +1,319 @@
+/*
+ * 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)
+    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 (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) == 0 &&
+        FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 0) {
+        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_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 (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP) == 1) {
+            r->wdogcount = 0;
+            wdogs = 0;
+        }
+    }
+
+    if (cmp_signal) {
+        if (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN) == 1) {
+            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) == 1 ||
+         FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 1)) {
+        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 (r->wdogunlock == 0) {
+            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 ((old_en_always ||
+             old_en_core_awake) == 1 &&
+            (new_en_always ||
+             new_en_core_awake) == 0) {
+            sifive_e_aon_wdt_update_wdogcount(r);
+        } else if ((old_en_always ||
+                    old_en_core_awake) == 0 &&
+                   (new_en_always ||
+                    new_en_core_awake) == 1) {
+            r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        }
+        r->wdogcfg = value;
+        r->wdogunlock = 0;
+        break;
+    }
+    case A_AON_WDT_WDOGCOUNT:
+        if (r->wdogunlock == 0) {
+            return;
+        }
+        r->wdogcount = value & R_AON_WDT_WDOGCOUNT_VALUE_MASK;
+        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 (r->wdogunlock == 0) {
+            return;
+        }
+        if (value == SIFIVE_E_AON_WDOGFEED) {
+            r->wdogcount = 0;
+            r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+        }
+        r->wdogunlock = 0;
+        break;
+    case A_AON_WDT_WDOGKEY:
+        if (value == SIFIVE_E_AON_WDOGKEY) {
+            r->wdogunlock = 1;
+        }
+        break;
+    case A_AON_WDT_WDOGCMP0:
+        if (r->wdogunlock == 0) {
+            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->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
+                                 sifive_e_aon_wdt_expired_cb, r);
+    r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
+    sysbus_init_irq(sbd, &r->wdog_irq);
+}
+
+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->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 v5 2/3] hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
  2023-06-08 16:45 [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
  2023-06-08 16:45 ` [PATCH v5 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
@ 2023-06-08 16:45 ` Tommy Wu
  2023-06-22  2:07   ` Alistair Francis
  2023-06-08 16:45 ` [PATCH v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
  2023-06-22  2:09 ` [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Alistair Francis
  3 siblings, 1 reply; 9+ messages in thread
From: Tommy Wu @ 2023-06-08 16:45 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang,
	liweiwei, philmd, 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         | 17 +++++++++++++++--
 include/hw/riscv/sifive_e.h |  9 ++++++---
 3 files changed, 22 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..0d37adc542 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"
 
@@ -185,6 +186,8 @@ static void sifive_e_soc_init(Object *obj)
     object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x1004, &error_abort);
     object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio,
                             TYPE_SIFIVE_GPIO);
+    object_initialize_child(obj, "riscv.sifive.e.aon", &s->aon,
+                            TYPE_SIFIVE_E_AON);
 }
 
 static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
@@ -223,10 +226,17 @@ 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);
     sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
 
+    /* AON */
+
+    if (!sysbus_realize(SYS_BUS_DEVICE(&s->aon), errp)) {
+        return;
+    }
+
+    /* Map AON registers */
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->aon), 0, memmap[SIFIVE_E_DEV_AON].base);
+
     /* GPIO */
 
     if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
@@ -245,6 +255,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..31180a680e 100644
--- a/include/hw/riscv/sifive_e.h
+++ b/include/hw/riscv/sifive_e.h
@@ -22,6 +22,7 @@
 #include "hw/riscv/riscv_hart.h"
 #include "hw/riscv/sifive_cpu.h"
 #include "hw/gpio/sifive_gpio.h"
+#include "hw/misc/sifive_e_aon.h"
 #include "hw/boards.h"
 
 #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
@@ -35,6 +36,7 @@ typedef struct SiFiveESoCState {
     /*< public >*/
     RISCVHartArrayState cpus;
     DeviceState *plic;
+    SiFiveEAONState aon;
     SIFIVEGPIOState gpio;
     MemoryRegion xip_mem;
     MemoryRegion mask_rom;
@@ -76,9 +78,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 v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e
  2023-06-08 16:45 [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
  2023-06-08 16:45 ` [PATCH v5 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
  2023-06-08 16:45 ` [PATCH v5 2/3] hw/riscv: sifive_e: " Tommy Wu
@ 2023-06-08 16:45 ` Tommy Wu
  2023-06-22  2:08   ` Alistair Francis
  2023-06-22  2:09 ` [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Alistair Francis
  3 siblings, 1 reply; 9+ messages in thread
From: Tommy Wu @ 2023-06-08 16:45 UTC (permalink / raw)
  To: qemu-devel, qemu-riscv
  Cc: alistair.francis, palmer, bin.meng, jim.shu, frank.chang,
	liweiwei, philmd, Tommy Wu, Thomas Huth

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>
Acked-by: Thomas Huth <thuth@redhat.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 5fa6833ad7..eb8d153a65 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -234,6 +234,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 v5 1/3] hw/misc: sifive_e_aon: Support the watchdog timer of HiFive 1 rev b.
  2023-06-08 16:45 ` [PATCH v5 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
@ 2023-06-22  2:04   ` Alistair Francis
  0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2023-06-22  2:04 UTC (permalink / raw)
  To: Tommy Wu
  Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
	jim.shu, frank.chang, liweiwei, philmd

On Fri, Jun 9, 2023 at 2:47 AM Tommy Wu <tommy.wu@sifive.com> 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>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/misc/Kconfig                |   3 +
>  hw/misc/meson.build            |   1 +
>  hw/misc/sifive_e_aon.c         | 319 +++++++++++++++++++++++++++++++++
>  include/hw/misc/sifive_e_aon.h |  60 +++++++
>  4 files changed, 383 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 e4c2149175..6996d265e4 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 78ca857c9d..6ac62e6751 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..4656457d0b
> --- /dev/null
> +++ b/hw/misc/sifive_e_aon.c
> @@ -0,0 +1,319 @@
> +/*
> + * 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)
> +    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 (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_ALWAYS) == 0 &&
> +        FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 0) {
> +        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_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 (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, ZEROCMP) == 1) {
> +            r->wdogcount = 0;
> +            wdogs = 0;
> +        }
> +    }
> +
> +    if (cmp_signal) {
> +        if (FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, RSTEN) == 1) {
> +            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) == 1 ||
> +         FIELD_EX32(r->wdogcfg, AON_WDT_WDOGCFG, EN_CORE_AWAKE) == 1)) {
> +        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 (r->wdogunlock == 0) {
> +            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 ((old_en_always ||
> +             old_en_core_awake) == 1 &&
> +            (new_en_always ||
> +             new_en_core_awake) == 0) {
> +            sifive_e_aon_wdt_update_wdogcount(r);
> +        } else if ((old_en_always ||
> +                    old_en_core_awake) == 0 &&
> +                   (new_en_always ||
> +                    new_en_core_awake) == 1) {
> +            r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        }
> +        r->wdogcfg = value;
> +        r->wdogunlock = 0;
> +        break;
> +    }
> +    case A_AON_WDT_WDOGCOUNT:
> +        if (r->wdogunlock == 0) {
> +            return;
> +        }
> +        r->wdogcount = value & R_AON_WDT_WDOGCOUNT_VALUE_MASK;
> +        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 (r->wdogunlock == 0) {
> +            return;
> +        }
> +        if (value == SIFIVE_E_AON_WDOGFEED) {
> +            r->wdogcount = 0;
> +            r->wdog_restart_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        }
> +        r->wdogunlock = 0;
> +        break;
> +    case A_AON_WDT_WDOGKEY:
> +        if (value == SIFIVE_E_AON_WDOGKEY) {
> +            r->wdogunlock = 1;
> +        }
> +        break;
> +    case A_AON_WDT_WDOGCMP0:
> +        if (r->wdogunlock == 0) {
> +            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->wdog_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                 sifive_e_aon_wdt_expired_cb, r);
> +    r->wdogclk_freq = SIFIVE_E_LFCLK_DEFAULT_FREQ;
> +    sysbus_init_irq(sbd, &r->wdog_irq);
> +}
> +
> +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->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	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 2/3] hw/riscv: sifive_e: Support the watchdog timer of HiFive 1 rev b.
  2023-06-08 16:45 ` [PATCH v5 2/3] hw/riscv: sifive_e: " Tommy Wu
@ 2023-06-22  2:07   ` Alistair Francis
  0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2023-06-22  2:07 UTC (permalink / raw)
  To: Tommy Wu
  Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
	jim.shu, frank.chang, liweiwei, philmd

On Fri, Jun 9, 2023 at 2:46 AM 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         | 17 +++++++++++++++--
>  include/hw/riscv/sifive_e.h |  9 ++++++---
>  3 files changed, 22 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..0d37adc542 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"
>
> @@ -185,6 +186,8 @@ static void sifive_e_soc_init(Object *obj)
>      object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x1004, &error_abort);
>      object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio,
>                              TYPE_SIFIVE_GPIO);
> +    object_initialize_child(obj, "riscv.sifive.e.aon", &s->aon,
> +                            TYPE_SIFIVE_E_AON);
>  }
>
>  static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
> @@ -223,10 +226,17 @@ 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);
>      sifive_e_prci_create(memmap[SIFIVE_E_DEV_PRCI].base);
>
> +    /* AON */
> +
> +    if (!sysbus_realize(SYS_BUS_DEVICE(&s->aon), errp)) {
> +        return;
> +    }
> +
> +    /* Map AON registers */
> +    sysbus_mmio_map(SYS_BUS_DEVICE(&s->aon), 0, memmap[SIFIVE_E_DEV_AON].base);
> +
>      /* GPIO */
>
>      if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
> @@ -245,6 +255,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..31180a680e 100644
> --- a/include/hw/riscv/sifive_e.h
> +++ b/include/hw/riscv/sifive_e.h
> @@ -22,6 +22,7 @@
>  #include "hw/riscv/riscv_hart.h"
>  #include "hw/riscv/sifive_cpu.h"
>  #include "hw/gpio/sifive_gpio.h"
> +#include "hw/misc/sifive_e_aon.h"
>  #include "hw/boards.h"
>
>  #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
> @@ -35,6 +36,7 @@ typedef struct SiFiveESoCState {
>      /*< public >*/
>      RISCVHartArrayState cpus;
>      DeviceState *plic;
> +    SiFiveEAONState aon;
>      SIFIVEGPIOState gpio;
>      MemoryRegion xip_mem;
>      MemoryRegion mask_rom;
> @@ -76,9 +78,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 v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e
  2023-06-08 16:45 ` [PATCH v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
@ 2023-06-22  2:08   ` Alistair Francis
  0 siblings, 0 replies; 9+ messages in thread
From: Alistair Francis @ 2023-06-22  2:08 UTC (permalink / raw)
  To: Tommy Wu
  Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
	jim.shu, frank.chang, liweiwei, philmd, Thomas Huth

On Fri, Jun 9, 2023 at 2:46 AM Tommy Wu <tommy.wu@sifive.com> 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>
> Acked-by: Thomas Huth <thuth@redhat.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  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 5fa6833ad7..eb8d153a65 100644
> --- a/tests/qtest/meson.build
> +++ b/tests/qtest/meson.build
> @@ -234,6 +234,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	[flat|nested] 9+ messages in thread

* Re: [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b.
  2023-06-08 16:45 [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
                   ` (2 preceding siblings ...)
  2023-06-08 16:45 ` [PATCH v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
@ 2023-06-22  2:09 ` Alistair Francis
  2023-06-27 14:14   ` Tommy Wu
  3 siblings, 1 reply; 9+ messages in thread
From: Alistair Francis @ 2023-06-22  2:09 UTC (permalink / raw)
  To: Tommy Wu
  Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
	jim.shu, frank.chang, liweiwei, philmd

On Fri, Jun 9, 2023 at 2:46 AM Tommy Wu <tommy.wu@sifive.com> wrote:
>
> 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.
>
> Changes since v4 ( Thank Phil for the feedback ):
> - Improve code style consistency.
> - Move the timer create function to the sifive_e_aon_init.
> - Allocate the sifive_e_aon device state in the SoC.
>
> 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

Do you mind rebasing this on
https://github.com/alistair23/qemu/tree/riscv-to-apply.next ? Then I
will apply it

Alistair

>
>  hw/misc/Kconfig                          |   3 +
>  hw/misc/meson.build                      |   1 +
>  hw/misc/sifive_e_aon.c                   | 319 ++++++++++++++++
>  hw/riscv/Kconfig                         |   1 +
>  hw/riscv/sifive_e.c                      |  17 +-
>  include/hw/misc/sifive_e_aon.h           |  60 +++
>  include/hw/riscv/sifive_e.h              |   9 +-
>  tests/qtest/meson.build                  |   3 +
>  tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
>  9 files changed, 858 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

* Re: [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b.
  2023-06-22  2:09 ` [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Alistair Francis
@ 2023-06-27 14:14   ` Tommy Wu
  0 siblings, 0 replies; 9+ messages in thread
From: Tommy Wu @ 2023-06-27 14:14 UTC (permalink / raw)
  To: Alistair Francis
  Cc: qemu-devel, qemu-riscv, alistair.francis, palmer, bin.meng,
	jim.shu, frank.chang, liweiwei, philmd

[-- Attachment #1: Type: text/plain, Size: 2837 bytes --]

Hi Alistair,
Thanks for the suggestion! I've rebased and sent patch v6.

Best Regards,
Tommy

On Thu, Jun 22, 2023 at 10:10 AM Alistair Francis <alistair23@gmail.com>
wrote:

> On Fri, Jun 9, 2023 at 2:46 AM Tommy Wu <tommy.wu@sifive.com> wrote:
> >
> > 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.
> >
> > Changes since v4 ( Thank Phil for the feedback ):
> > - Improve code style consistency.
> > - Move the timer create function to the sifive_e_aon_init.
> > - Allocate the sifive_e_aon device state in the SoC.
> >
> > 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
>
> Do you mind rebasing this on
> https://github.com/alistair23/qemu/tree/riscv-to-apply.next ? Then I
> will apply it
>
> Alistair
>
> >
> >  hw/misc/Kconfig                          |   3 +
> >  hw/misc/meson.build                      |   1 +
> >  hw/misc/sifive_e_aon.c                   | 319 ++++++++++++++++
> >  hw/riscv/Kconfig                         |   1 +
> >  hw/riscv/sifive_e.c                      |  17 +-
> >  include/hw/misc/sifive_e_aon.h           |  60 +++
> >  include/hw/riscv/sifive_e.h              |   9 +-
> >  tests/qtest/meson.build                  |   3 +
> >  tests/qtest/sifive-e-aon-watchdog-test.c | 450 +++++++++++++++++++++++
> >  9 files changed, 858 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
> >
> >
>

[-- Attachment #2: Type: text/html, Size: 3691 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-06-27 14:14 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-08 16:45 [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Tommy Wu
2023-06-08 16:45 ` [PATCH v5 1/3] hw/misc: sifive_e_aon: Support " Tommy Wu
2023-06-22  2:04   ` Alistair Francis
2023-06-08 16:45 ` [PATCH v5 2/3] hw/riscv: sifive_e: " Tommy Wu
2023-06-22  2:07   ` Alistair Francis
2023-06-08 16:45 ` [PATCH v5 3/3] tests/qtest: sifive-e-aon-watchdog-test.c: Add QTest of watchdog of sifive_e Tommy Wu
2023-06-22  2:08   ` Alistair Francis
2023-06-22  2:09 ` [PATCH v5 0/3] Implement the watchdog timer of HiFive 1 rev b Alistair Francis
2023-06-27 14:14   ` Tommy Wu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.