Hi Brian,
On 18/7/26 03:32, Brian Cain wrote:
Implement the QCT QTimer generic timer device used by Hexagon DSP
systems.
Co-authored-by: Damien Hedde <[email protected]>
Co-authored-by: Tobias Röhmel <[email protected]>
Co-authored-by: Sid Manning <[email protected]>
Co-authored-by: Thomas Marceron <[email protected]>
Co-authored-by: Mahmoud Kamel <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
MAINTAINERS | 2 +
include/hw/timer/qct-qtimer.h | 78 +++++
hw/timer/qct-qtimer.c | 613 ++++++++++++++++++++++++++++++++++
hw/timer/Kconfig | 3 +
hw/timer/meson.build | 2 +
hw/timer/trace-events | 5 +
6 files changed, 703 insertions(+)
create mode 100644 include/hw/timer/qct-qtimer.h
create mode 100644 hw/timer/qct-qtimer.c
diff --git a/MAINTAINERS b/MAINTAINERS
index a5df21aa12d..2c73705c727 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -253,6 +253,8 @@ F: target/hexagon/
F: hw/intc/hex-l2vic.c
F: include/hw/intc/hex-l2vic.h
F: tests/qtest/l2vic-test.c
+F: hw/timer/qct-qtimer.c
+F: include/hw/timer/qct-qtimer.h
X: target/hexagon/idef-parser/
X: target/hexagon/gen_idef_parser_funcs.py
F: linux-user/hexagon/
diff --git a/include/hw/timer/qct-qtimer.h b/include/hw/timer/qct-qtimer.h
new file mode 100644
index 00000000000..d2ef9447b26
--- /dev/null
+++ b/include/hw/timer/qct-qtimer.h
@@ -0,0 +1,78 @@
+/*
+ * Qualcomm QCT QTimer
+ *
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_TIMER_QCT_QTIMER_H
+#define HW_TIMER_QCT_QTIMER_H
+
+#include "qom/object.h"
+
+#define TYPE_QCT_QTIMER "qct-qtimer"
+
+#define QCT_QTIMER_TIMER_FRAME_ELTS (16)
+#define QCT_QTIMER_TIMER_VIEW_ELTS (2)
+
+#define QCT_QTIMER_AC_CNTFRQ (0x000)
+#define QCT_QTIMER_AC_CNTSR (0x004)
+#define QCT_QTIMER_AC_CNTTID_0 (0x08)
+#define QCT_QTIMER_AC_CNTACR_START (0x40)
+#define QCT_QTIMER_AC_CNTACR_END (0x5c)
+#define QCT_QTIMER_AC_CNTTID_1 (0x108)
+#define QCT_QTIMER_AC_CNTACR_RWPT (1 << 5) /* R/W of CNTP_* regs */
+#define QCT_QTIMER_AC_CNTACR_RWVT (1 << 4) /* R/W of CNTV_* regs */
+#define QCT_QTIMER_AC_CNTACR_RVOFF (1 << 3) /* R/W of CNTVOFF register */
+#define QCT_QTIMER_AC_CNTACR_RFRQ (1 << 2) /* R/W of CNTFRQ register */
+#define QCT_QTIMER_AC_CNTACR_RPVCT (1 << 1) /* R/W of CNTVCT register */
+#define QCT_QTIMER_AC_CNTACR_RPCT (1 << 0) /* R/W of CNTPCT register */
+#define QCT_QTIMER_VERSION (0x0fd0)
+
+#define QCT_QTIMER_CNTPCT_LO (0x000)
+#define QCT_QTIMER_CNTPCT_HI (0x004)
+#define QCT_QTIMER_CNT_FREQ (0x010)
+#define QCT_QTIMER_CNTPL0ACR (0x014)
+#define QCT_QTIMER_CNTPL0ACR_PL0CTEN (1 << 9)
+#define QCT_QTIMER_CNTPL0ACR_PL0TVEN (1 << 8)
+#define QCT_QTIMER_CNTPL0ACR_PL0VCTEN (1 << 1)
+#define QCT_QTIMER_CNTPL0ACR_PL0PCTEN (1 << 0)
+#define QCT_QTIMER_CNTP_CVAL_LO (0x020)
+#define QCT_QTIMER_CNTP_CVAL_HI (0x024)
+#define QCT_QTIMER_CNT_MASK 0x00ffffffffffffffULL
+#define QCT_QTIMER_CNT_HI_BITS 24
+#define QCT_QTIMER_CNTP_TVAL (0x028)
+#define QCT_QTIMER_CNTP_CTL (0x02c)
+#define QCT_QTIMER_CNTP_CTL_ENABLE (1 << 0)
+#define QCT_QTIMER_CNTP_CTL_INTEN (1 << 1)
+#define QCT_QTIMER_CNTP_CTL_ISTAT (1 << 2)
The register related definitions aren't consumed outside of the
implementation, so no need to expose them, they could be moved
to the single place using them, the source file.
+
+/* QTimer interface for external access from hexagon_globalreg */
+#define TYPE_QCT_QTIMER_INTERFACE "qct-qtimer-if"
+
+typedef struct QctQtimerInterface QctQtimerInterface;
+
+typedef struct QctQtimerInterfaceClass {
+ InterfaceClass parent_class;
+
+ /* Read the live physical counter, backing HEX_SREG_TIMERLO/TIMERHI */
+ uint32_t (*get_timer_lo)(QctQtimerInterface *qtimer);
const qtimer
+ uint32_t (*get_timer_hi)(QctQtimerInterface *qtimer);
const qtimer
+} QctQtimerInterfaceClass;
diff --git a/hw/timer/qct-qtimer.c b/hw/timer/qct-qtimer.c
new file mode 100644
index 00000000000..fd56a7118b1
--- /dev/null
+++ b/hw/timer/qct-qtimer.c
@@ -0,0 +1,613 @@
+static const MemoryRegionOps qct_qtimer_ac_ops = {
+ .read = qct_qtimer_ac_read,
+ .write = qct_qtimer_ac_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
Missing .impl = {4, 4}
+};
+static const Property qct_qtimer_properties[] = {
+ DEFINE_PROP_UINT32("freq", QCTQtimerState, freq, QTIMER_DEFAULT_FREQ_HZ),
"freq-hz", freq_hz if possible.
+ DEFINE_PROP_UINT32("freq-scale", QCTQtimerState, freq_scale, 1),
+ DEFINE_PROP_UINT32("nr_frames", QCTQtimerState, nr_frames, 2),
+ DEFINE_PROP_UINT32("nr_views", QCTQtimerState, nr_views, 1),
+ DEFINE_PROP_UINT32("frame_stride", QCTQtimerState, frame_stride, 0x1000),
+ DEFINE_PROP_UINT32("cnttid_0", QCTQtimerState, cnttid_0, 0x11),
+ DEFINE_PROP_UINT32("cnttid_1", QCTQtimerState, cnttid_1, 0x0),
+};
+
+static void qct_qtimer_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ device_class_set_props(dc, qct_qtimer_properties);
+ dc->realize = qct_qtimer_realize;
Missing unrealize.
+ dc->vmsd = &vmstate_qct_qtimer;
+ rc->phases.hold = qct_qtimer_reset_hold;
+}
+static void qct_qtimer_register_types(void)
+{
+ type_register_static(&qct_qtimer_interface_info);
+ type_register_static(&qct_qtimer_info);
+}
+
+type_init(qct_qtimer_register_types)
Prefer DEFINE_TYPES.
Regards,
Phil.