From nobody Sat Jul 25 13:39:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=oss.qualcomm.com ARC-Seal: i=1; a=rsa-sha256; t=1784338413; cv=none; d=zohomail.com; s=zohoarc; b=jQYwltkmaNgHXkz8NQuktTfzkDzOygHuWuFph8hDM6jUw6/WFmZcCCy/Tv7m9lqRxjHTdNE+olWRW+v5f9wS2/PR+UeDBYVQR6KoN4XiIf4yb448vHSMiE/bVanGvr+0DT4hkl4rgTuBNoUeT4SOgLpEwjObtLipu73o0RIQpFU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784338413; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=arAWEpX2IuiV4HStaqLiEG+FyS/7kUgJYj/B7EzJHRQ=; b=N8NefAwIgPkiOeD7kN2yFIz6lX6qgjNTioAi1h5QLwMommbEevDQTsavWz6afLqOQMpzg9t0HX0QkpJjEkeoOmrzevnclG0x6V6ro7MYdhOrwDGUvVyzmoWzLc2YlKKVlCD6dUjmtZ3DkzkZZRBSbNf/a9Jku0ly1WXKUa0vAFQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784338413610235.26771910575235; Fri, 17 Jul 2026 18:33:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wktvJ-0005Y7-1o; Fri, 17 Jul 2026 21:33:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktvA-0005Wc-0K for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:52 -0400 Received: from mx0a-0031df01.pphosted.com ([205.220.168.131]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktv6-0005v5-Gn for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:51 -0400 Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66HNEMrB3308669 for ; Sat, 18 Jul 2026 01:32:46 GMT Received: from mail-pl1-f197.google.com (mail-pl1-f197.google.com [209.85.214.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4ffrqd9f7f-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sat, 18 Jul 2026 01:32:46 +0000 (GMT) Received: by mail-pl1-f197.google.com with SMTP id d9443c01a7336-2cacf17c7e0so74122045ad.0 for ; Fri, 17 Jul 2026 18:32:46 -0700 (PDT) Received: from hu-bcain-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3142a1ddeb6sm13393494eec.20.2026.07.17.18.32.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jul 2026 18:32:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:content-type:date:from :in-reply-to:message-id:mime-version:references:subject:to; s= qcppdkim1; bh=arAWEpX2IuiV4HStaqLiEG+FyS/7kUgJYj/B7EzJHRQ=; b=Kq Of0TlEhkLRtXpNVADO/SpGgltDj/6XdNrx5pX6SgNgClT+x6X0ioJ7t04Pz+lFEm rNcdEC6rne3YybckKI0rxOFQnxZtG3CFSUZ/HkDA1tRAng6xpba4KPyVa7yyXsMA UP/dYO5K57u0qkQvFJiZtMV8o9Lzrq8E7EEw7TCmC1R6Oi3SUvZBqjc9vb9EA8yi Gqv095NVpVq+5xFc5WHDcTSq6lRLZG5IQMMBPaGEV8HpXsMkRgxZgFscmTOlZAMG nsZgXKkIXIi4dzEnWN/iAAbB9aj5/CbIvxmbiyqbB/68eOrF4Wape/SWRTw8KTaN 35QLe3mc+5jWhzsnI73Q== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1784338365; x=1784943165; darn=nongnu.org; h=content-transfer-encoding:content-type:content-type:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from:from:to :cc:subject:date:message-id:reply-to:content-type; bh=arAWEpX2IuiV4HStaqLiEG+FyS/7kUgJYj/B7EzJHRQ=; b=D/XQc8wZN6Ek7nGrPZbNUktlDNOU21uUGqL4LvkIxj8h0Io8n7cIQV1bjdDdbRJGs7 p3rm5/M9ZTOSjWppz/yEMAYIUlwIQpoVRd+oFosNQL1ktZ+QL+dOjWubgH/keJiN20FY QUGeZazZcqSlzow54/XFnmkWf8uSRIKmLNcurlFo9iFBqT0X2PZO9HbD3Uo/rNIpV8Xz CtbBwPXyJufUi5e+LhMJ+x6UGbzq9OHbhww3bwh+cOe7WFcm32L7TnKNuwcpzBK03LtS w3S+spat+2Nthg+XwurckJ5xdwCHLqDtP6//4XIDjTFv2tcwD8Fu85ZdgokPpPZrzjJN xfaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784338365; x=1784943165; h=content-transfer-encoding:content-type:content-type:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=arAWEpX2IuiV4HStaqLiEG+FyS/7kUgJYj/B7EzJHRQ=; b=lsOtgoze7aNputIrAdSPz+nDdXAchDOYWRVG8Vl9OKgEeS9MWJq2EmQyBqbCuc3BCx mtJuW6WL3+SyDXexbWG5ecvtKqtbydPQNQH0fENzGD7RvCtRZFFnfawOKvc54KW4MSWY SssjkOS7DcvCGKeCqrWDWhhnweG9L0oRyvF1oyYoJnWbO4SzBLxu/inB4lbDS/ot+cyk uTg+JaEOEjBXg6W5zqCIC1SsmM8M4HTlxfCX7BahxrtSieu3TPFdqqNmLGexF2k6jU2H IAfT/EDGOAN4rThzmwSbDjO9iB0cEKqxBE8MFZiRylK4f1dKAxyagxXnLQ9Ik9IXJ+Jx geVA== X-Gm-Message-State: AOJu0YyBBpV181bGlELPIgRH2YUskkqlZxKvANZ7OM9d5WwO6W7uWFHb 4vMY8DFtTpbzxQZNwrz9O7Po4cyhXknJsreQfAeAcFvAtgS+s82Y1Mr6q2TtInu4lwnkGTXuGje 5rFv4PkJ5SbNhzE9xLFb4XKFmAScZCfAsGBit5TsTNCpFbBxSzbuO+IxvLDaAF4Hl3g== X-Gm-Gg: AfdE7cnEf6ka+BbGVPveUh1oxkT4FQpo66atP0r0BIY156rgzctrGMZwO0xTaZ62xVU aEtDUtSXOsW86I7JV1xR0fd6kPsvaCmlCv3+bSmW6DRscnYeFZYRYd0bTf//X7STz3ZdR9MFLSs Flm3kV+p8KNgcD1NYTjy9AgJ8QWJEUNfwj2Qg5I1IyG3eLM3kCapMsPmb5N0Yj4VdGs82jWDx8Y QM+amP2rqpBZEfdvTrY0WESfah0KcPodroq4D2CPI8L+NnHEnL7u3hxIiRZgLn2FCDlAMHd2NX3 nAh4Ska5kIlThMNLr5TB2v+0JwtPTGNj6TzFE2hCq9LKaSzbO6RnDIaIcJPdd7pXQrfxsY9ovN9 /DZI8Sqi0ERSG4DZfJINVjfKWDPFaiklgw9qf3cFf2wtF4JfL X-Received: by 2002:a17:90b:3886:b0:36b:944b:fd81 with SMTP id 98e67ed59e1d1-38e4b3d27c3mr5392059a91.4.1784338365188; Fri, 17 Jul 2026 18:32:45 -0700 (PDT) X-Received: by 2002:a17:90b:3886:b0:36b:944b:fd81 with SMTP id 98e67ed59e1d1-38e4b3d27c3mr5392016a91.4.1784338364469; Fri, 17 Jul 2026 18:32:44 -0700 (PDT) From: Brian Cain To: qemu-devel@nongnu.org Cc: philmd@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, Paolo Bonzini , Laurent Vivier , Brian Cain , Fabiano Rosas , matheus.bernardino@oss.qualcomm.com, Damien Hedde , =?UTF-8?q?Tobias=20R=C3=B6hmel?= , Sid Manning , Thomas Marceron , Mahmoud Kamel Subject: [PATCH 1/3] hw/timer: Add QCT QTimer device model Date: Fri, 17 Jul 2026 18:32:39 -0700 Message-Id: <20260718013241.1550124-2-brian.cain@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> References: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: TdRgzC08UvGBCMV8B3_O9-AbyMhttxcQ X-Authority-Analysis: v=2.4 cv=DbYnbPtW c=1 sm=1 tr=0 ts=6a5ad7be cx=c_pps a=cmESyDAEBpBGqyK7t0alAg==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yOCtJkima9RkubShWh1s:22 a=1cGLs3X8AAAA:8 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=EJJHuv5FfEzJzECx-9QA:9 a=QEXdDO2ut3YA:10 a=1OuFwYUASf3TG4hYMiVC:22 a=d8ghUycwObenwynNfMyN:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: TdRgzC08UvGBCMV8B3_O9-AbyMhttxcQ X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE4MDAxMSBTYWx0ZWRfXywWn+strwmbS kWal/fgHe2w4ffyAocsIqPdI90SPrg2vWZL65554O7Gce+uftOalgw6EXKkfqQXD8TCUhVpdsE+ RGNthJOws2IV0Go3vnHhW3P7coC6cFc= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE4MDAxMSBTYWx0ZWRfX/eiqBF9cBrBp 3g2aZJ/PyzA+kGoubx6cTGlb1gKcOP5vhz3heTk/brSdqKTYLlLUhgzkUM9+I55RsjBg9c/4HiW +NtyB4eCV2P3SyL1+5L+e8/xPD8TitfLz68F43At7a7ijFSf1KKZ0pZgX2LfqKuKP3zhQEnt0Ah Sde1sC9GYLhe9h6RNA98jt3o4cefYA4QcboFronztOTB8tlK/43dHAncTPne3MjxW6dTsH7AD/L O4zfQLrX+rIBGFt3TKDRXr78Ee8j+MbMximJT8g96b5MmdiJg2LlEjsRzGqrvy5hryLtp4QWr0O pBIkqzLYEE30+Q4IXRLFLtR8V2/XGn2w0u/a59DxoVWr5GtoVmUeaszJ/CwZDxdA5A0hDh3mdi3 ocHUcCIL8tdfCNtbPqMhTQb5korEayLf6R9UzuQ51FHqXownAGOxrrggqZyztu5bBlYRFmRrDAj CO0bQvSakglqiFnrCgQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-17_07,2026-07-17_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=0 lowpriorityscore=0 phishscore=0 bulkscore=0 malwarescore=0 clxscore=1015 priorityscore=1501 adultscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607180011 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=205.220.168.131; envelope-from=brian.cain@oss.qualcomm.com; helo=mx0a-0031df01.pphosted.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @qualcomm.com) X-ZM-MESSAGEID: 1784338417046158500 Content-Type: text/plain; charset="utf-8" Implement the QCT QTimer generic timer device used by Hexagon DSP systems. Co-authored-by: Damien Hedde Co-authored-by: Tobias R=C3=B6hmel Co-authored-by: Sid Manning Co-authored-by: Thomas Marceron Co-authored-by: Mahmoud Kamel Signed-off-by: Brian Cain --- 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) + +/* 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); + uint32_t (*get_timer_hi)(QctQtimerInterface *qtimer); +} QctQtimerInterfaceClass; + +DECLARE_OBJ_CHECKERS(QctQtimerInterface, QctQtimerInterfaceClass, + QCT_QTIMER_INTERFACE, TYPE_QCT_QTIMER_INTERFACE); + +static inline uint32_t qct_qtimer_get_timer_lo(QctQtimerInterface *qtimer) +{ + QctQtimerInterfaceClass *k =3D QCT_QTIMER_INTERFACE_GET_CLASS(qtimer); + return k->get_timer_lo(qtimer); +} + +static inline uint32_t qct_qtimer_get_timer_hi(QctQtimerInterface *qtimer) +{ + QctQtimerInterfaceClass *k =3D QCT_QTIMER_INTERFACE_GET_CLASS(qtimer); + return k->get_timer_hi(qtimer); +} + +#endif /* HW_TIMER_QCT_QTIMER_H */ 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 @@ +/* + * Qualcomm QCT QTimer + * + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hw/core/irq.h" +#include "hw/core/qdev-properties.h" +#include "hw/core/sysbus.h" +#include "hw/timer/qct-qtimer.h" +#include "migration/vmstate.h" +#include "qemu/bitops.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "trace.h" + +#define QTIMER_MEM_SIZE_BYTES 0x1000 +#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL + +OBJECT_DECLARE_SIMPLE_TYPE(QCTQtimerState, QCT_QTIMER) + +typedef struct QCTHextimerState { + QCTQtimerState *qtimer; + QEMUTimer *timer; /* one-shot deadline timer */ + int64_t offset_ns; /* QEMU_CLOCK_VIRTUAL ns at which cntpct =3D= =3D 0 */ + uint64_t cntval; /* 64-bit physical timer compare value */ + uint32_t control; + uint32_t cnt_ctrl; + uint32_t cntpl0acr; + uint32_t freq; + uint32_t int_level; + qemu_irq irq; +} QCTHextimerState; + +struct QCTQtimerState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + MemoryRegion view_iomem; + uint32_t secure; + QCTHextimerState timer[QCT_QTIMER_TIMER_FRAME_ELTS]; + uint32_t freq; + uint32_t nr_frames; + uint32_t nr_views; + uint32_t frame_stride; + uint32_t cnttid_0; + uint32_t cnttid_1; + uint32_t freq_scale; +}; + +/* + * QTimer version register: + * + * 3 2 1 + * 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Major | Minor | Step | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define QCT_QTIMER_VERSION_VALUE 0x20020000 + +/* Counter value derived on-demand from QEMU_CLOCK_VIRTUAL. */ +static uint64_t hex_timer_now(QCTHextimerState *s) +{ + int64_t now =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + uint32_t scaler; + uint64_t scaled_elapsed; + + if (now <=3D s->offset_ns) { + return 0; + } + scaler =3D MAX(s->qtimer->freq_scale, 1u); + scaled_elapsed =3D (uint64_t)(now - s->offset_ns) / scaler; + return muldiv64(scaled_elapsed, s->freq, NANOSECONDS_PER_SECOND) & + QCT_QTIMER_CNT_MASK; +} + +/* Arm (or disarm) the one-shot deadline timer. */ +static void hex_timer_rearm(QCTHextimerState *s) +{ + uint32_t scaler; + uint64_t base_ns; + int64_t deadline_ns; + + if (!(s->control & QCT_QTIMER_CNTP_CTL_ENABLE)) { + timer_del(s->timer); + return; + } + + scaler =3D MAX(s->qtimer->freq_scale, 1u); + base_ns =3D muldiv64(s->cntval, NANOSECONDS_PER_SECOND, s->freq); + if (base_ns > + ((uint64_t)INT64_MAX - (uint64_t)s->offset_ns - 1) / scaler) { + timer_del(s->timer); + return; + } + /* + * muldiv64() truncates, so the computed deadline can land up to 1 ns + * before the true cntval crossing. Add 1 ns so hex_timer_now() is + * guaranteed to be >=3D cntval when the QEMUTimer fires; without this, + * hex_timer_tick() would re-arm at the same deadline and loop. + */ + deadline_ns =3D s->offset_ns + (int64_t)(base_ns * scaler) + 1; + timer_mod(s->timer, deadline_ns); +} + +static void hex_timer_update(QCTHextimerState *s) +{ + int level =3D s->int_level && + (s->control & QCT_QTIMER_CNTP_CTL_ENABLE) && + !(s->control & QCT_QTIMER_CNTP_CTL_INTEN); + + trace_qtimer_interrupt(); + qemu_set_irq(s->irq, level); +} + +/* + * Access-control (AC) region: offsets below 0x1000, gates CNTFRQ/CNTSR/ + * CNTTID/CNTACR per frame plus the shared VERSION register. + */ +static uint64_t qct_qtimer_ac_read(void *opaque, hwaddr offset, unsigned s= ize) +{ + QCTQtimerState *s =3D opaque; + uint32_t frame; + + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + return s->freq; + case QCT_QTIMER_AC_CNTSR: + return s->secure; + case QCT_QTIMER_AC_CNTTID_0: + return s->cnttid_0; + case QCT_QTIMER_AC_CNTTID_1: + return s->cnttid_1; + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame =3D (offset - QCT_QTIMER_AC_CNTACR_START) / 4; + if (frame >=3D s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTACR offset 0x%x\n", + __func__, (int)offset); + return 0; + } + return s->timer[frame].cnt_ctrl; + case QCT_QTIMER_VERSION: + return QCT_QTIMER_VERSION_VALUE; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return 0; + } +} + +static void qct_qtimer_ac_write(void *opaque, hwaddr offset, uint64_t valu= e, + unsigned size) +{ + QCTQtimerState *s =3D opaque; + uint32_t frame; + + switch (offset) { + case QCT_QTIMER_AC_CNTFRQ: + s->freq =3D value; + return; + case QCT_QTIMER_AC_CNTSR: + if (value > 0xff) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTSR value 0x%x\n", + __func__, (int)value); + return; + } + s->secure =3D value; + return; + case QCT_QTIMER_AC_CNTACR_START ... QCT_QTIMER_AC_CNTACR_END: + frame =3D (offset - QCT_QTIMER_AC_CNTACR_START) / 4; + if (frame >=3D s->nr_frames) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad CNTACR offset 0x%x\n", + __func__, (int)offset); + return; + } + s->timer[frame].cnt_ctrl =3D value; + return; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return; + } +} + +static const MemoryRegionOps qct_qtimer_ac_ops =3D { + .read =3D qct_qtimer_ac_read, + .write =3D qct_qtimer_ac_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + .unaligned =3D false, + }, +}; + +/* + * View region: a flat array of (frame, view) slots, each frame_stride + * bytes wide, holding the per-frame CNTPCT/CNTP_CVAL/CNTP_TVAL/CNTP_CTL + * register set. + */ +static QCTHextimerState *qct_qtimer_demux(QCTQtimerState *s, hwaddr offset, + uint32_t *reg_offset, + uint32_t *view) +{ + uint32_t stride =3D s->frame_stride; + uint32_t stride_shift =3D ctz32(stride); + uint32_t slot_nr =3D (offset & (0xf * stride)) >> stride_shift; + uint32_t frame =3D slot_nr / s->nr_views; + + *reg_offset =3D offset & (stride - 1); + *view =3D slot_nr % s->nr_views; + if (frame >=3D s->nr_frames) { + return NULL; + } + return &s->timer[frame]; +} + +/* Frames 8+ share cnttid_1; each frame's second view is gated by a bit. */ +static bool qct_qtimer_view_visible(QCTQtimerState *s, uint32_t frame, + uint32_t view) +{ + uint32_t cnttid =3D frame < 8 ? s->cnttid_0 : s->cnttid_1; + uint32_t frame_idx =3D frame < 8 ? frame : frame - 8; + + return !view || (cnttid & (0x4 << (frame_idx * 4))); +} + +static MemTxResult hex_timer_read(void *opaque, hwaddr offset, uint64_t *d= ata, + unsigned size, MemTxAttrs attrs) +{ + QCTQtimerState *qs =3D opaque; + uint32_t reg_offset; + uint32_t view; + QCTHextimerState *s =3D qct_qtimer_demux(qs, offset, ®_offset, &vie= w); + uint32_t frame; + + if (!s) { + *data =3D 0; + return MEMTX_ACCESS_ERROR; + } + frame =3D s - qs->timer; + + trace_qtimer_read(offset); + + if (!qct_qtimer_view_visible(qs, frame, view)) { + *data =3D 0; + return MEMTX_OK; + } + + switch (reg_offset) { + case QCT_QTIMER_CNT_FREQ: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RFRQ)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & (QCT_QTIMER_CNTPL0ACR_PL0PCTEN | + QCT_QTIMER_CNTPL0ACR_PL0VCTEN))) { + return MEMTX_ACCESS_ERROR; + } + *data =3D s->freq; + return MEMTX_OK; + case QCT_QTIMER_CNTP_CVAL_LO: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + *data =3D extract64(s->cntval, 0, 32); + return MEMTX_OK; + case QCT_QTIMER_CNTP_CVAL_HI: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + /* HI half is 24-bit per TRM; bits [31:24] are reserved. */ + *data =3D extract64(s->cntval, 32, QCT_QTIMER_CNT_HI_BITS); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_LO: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RPCT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0PCTEN)) { + return MEMTX_ACCESS_ERROR; + } + *data =3D extract64(hex_timer_now(s), 0, 32); + return MEMTX_OK; + case QCT_QTIMER_CNTPCT_HI: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RPCT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0PCTEN)) { + return MEMTX_ACCESS_ERROR; + } + *data =3D extract64(hex_timer_now(s), 32, QCT_QTIMER_CNT_HI_BITS); + return MEMTX_OK; + case QCT_QTIMER_CNTP_TVAL: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + *data =3D (uint32_t)(int32_t)(int64_t)(s->cntval - hex_timer_now(s= )); + return MEMTX_OK; + case QCT_QTIMER_CNTP_CTL: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + /* + * CNTP_CTL: bit 0 EN, bit 1 IMASK, bit 2 ISTAT (interrupt + * pending). ISTAT tracks int_level and is read-only. + */ + *data =3D s->control | ((s->int_level & 0x1) << 2); + return MEMTX_OK; + case QCT_QTIMER_CNTPL0ACR: + *data =3D view ? 0 : s->cntpl0acr; + return MEMTX_OK; + case QCT_QTIMER_VERSION: + *data =3D QCT_QTIMER_VERSION_VALUE; + return MEMTX_OK; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + *data =3D 0; + return MEMTX_ACCESS_ERROR; + } +} + +static MemTxResult hex_timer_write(void *opaque, hwaddr offset, + uint64_t value, unsigned size, + MemTxAttrs attrs) +{ + QCTQtimerState *qs =3D opaque; + uint32_t reg_offset; + uint32_t view; + QCTHextimerState *s =3D qct_qtimer_demux(qs, offset, ®_offset, &vie= w); + uint32_t frame; + + if (!s) { + return MEMTX_ACCESS_ERROR; + } + frame =3D s - qs->timer; + + trace_qtimer_write(offset, value); + + if (!qct_qtimer_view_visible(qs, frame, view)) { + return MEMTX_OK; + } + + switch (reg_offset) { + case QCT_QTIMER_CNTP_CVAL_LO: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + s->int_level =3D 0; + s->cntval =3D deposit64(s->cntval, 0, 32, value); + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_CVAL_HI: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + s->int_level =3D 0; + /* HI half is 24-bit per TRM; bits [31:24] are reserved. */ + s->cntval =3D deposit64(s->cntval, 32, QCT_QTIMER_CNT_HI_BITS, val= ue) & + QCT_QTIMER_CNT_MASK; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_CTL: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + /* ISTAT (bit 2) is read-only; keep SW writes from polluting it. */ + s->control =3D value & ~QCT_QTIMER_CNTP_CTL_ISTAT; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTP_TVAL: + if (!(s->cnt_ctrl & QCT_QTIMER_AC_CNTACR_RWPT)) { + return MEMTX_ACCESS_ERROR; + } + if (view && !(s->cntpl0acr & QCT_QTIMER_CNTPL0ACR_PL0CTEN)) { + return MEMTX_ACCESS_ERROR; + } + /* TVAL write: CVAL =3D CNTPCT + TVAL (TVAL is signed 32-bit). */ + s->int_level =3D 0; + s->cntval =3D (hex_timer_now(s) + (int64_t)(int32_t)value) & + QCT_QTIMER_CNT_MASK; + hex_timer_rearm(s); + break; + case QCT_QTIMER_CNTPL0ACR: + if (!view) { + s->cntpl0acr =3D value; + } + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%x\n", __func__, + (int)offset); + return MEMTX_ACCESS_ERROR; + } + hex_timer_update(s); + return MEMTX_OK; +} + +static void hex_timer_tick(void *opaque) +{ + QCTHextimerState *s =3D opaque; + uint64_t now =3D hex_timer_now(s); + uint64_t diff56 =3D (now - s->cntval) & QCT_QTIMER_CNT_MASK; + int64_t signed_diff =3D (int64_t)(diff56 << 8) >> 8; + + if (signed_diff >=3D 0) { + s->int_level =3D 1; + hex_timer_update(s); + } else { + hex_timer_rearm(s); + } +} + +static const MemoryRegionOps hex_timer_ops =3D { + .read_with_attrs =3D hex_timer_read, + .write_with_attrs =3D hex_timer_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .valid =3D { + .min_access_size =3D 4, + .max_access_size =3D 8, + .unaligned =3D false, + }, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static const VMStateDescription vmstate_qct_hextimer =3D { + .name =3D "qct-hextimer", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_UINT32(control, QCTHextimerState), + VMSTATE_UINT32(cnt_ctrl, QCTHextimerState), + VMSTATE_INT64(offset_ns, QCTHextimerState), + VMSTATE_UINT64(cntval, QCTHextimerState), + VMSTATE_UINT32(cntpl0acr, QCTHextimerState), + VMSTATE_UINT32(int_level, QCTHextimerState), + VMSTATE_TIMER_PTR(timer, QCTHextimerState), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_qct_qtimer =3D { + .name =3D "qct-qtimer", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT_ARRAY(timer, QCTQtimerState, QCT_QTIMER_TIMER_FRAME= _ELTS, + 1, vmstate_qct_hextimer, QCTHextimerState), + VMSTATE_END_OF_LIST() + } +}; + +static void qct_qtimer_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + QCTQtimerState *s =3D QCT_QTIMER(dev); + unsigned int i; + + if (s->nr_frames > QCT_QTIMER_TIMER_FRAME_ELTS) { + error_setg(errp, "nr_frames too high"); + return; + } + if (s->nr_views > QCT_QTIMER_TIMER_VIEW_ELTS) { + error_setg(errp, "nr_views too high"); + return; + } + + memory_region_init_io(&s->iomem, OBJECT(s), &qct_qtimer_ac_ops, s, + "qct-qtimer-ac", QTIMER_MEM_SIZE_BYTES); + sysbus_init_mmio(sbd, &s->iomem); + + memory_region_init_io(&s->view_iomem, OBJECT(s), &hex_timer_ops, s, + "qct-qtimer-view", + (uint64_t)s->frame_stride * s->nr_frames * + s->nr_views); + sysbus_init_mmio(sbd, &s->view_iomem); + + for (i =3D 0; i < s->nr_frames; i++) { + QCTHextimerState *t =3D &s->timer[i]; + + t->qtimer =3D s; + t->freq =3D QTIMER_DEFAULT_FREQ_HZ; + s->secure |=3D (1 << i); + + sysbus_init_irq(sbd, &t->irq); + t->timer =3D timer_new_ns(QEMU_CLOCK_VIRTUAL, hex_timer_tick, t); + } +} + +static void qct_qtimer_reset_hold(Object *obj, ResetType type) +{ + QCTQtimerState *s =3D QCT_QTIMER(obj); + unsigned int i; + + for (i =3D 0; i < s->nr_frames; i++) { + QCTHextimerState *t =3D &s->timer[i]; + + /* + * Per TRM: CTL =3D 0 (EN=3D0, IMASK=3D0, ISTAT=3D0), CVAL =3D 0 s= o that + * TVAL (=3D CVAL - CNTPCT) also reads 0 at reset. The QEMUTimer is + * only armed when SW sets CTL.EN=3D1, so cntval=3D0 does not caus= e a + * spurious fire before SW programs the compare value. + */ + t->control =3D 0; + t->cnt_ctrl =3D QCT_QTIMER_AC_CNTACR_RWPT | QCT_QTIMER_AC_CNTACR_R= WVT | + QCT_QTIMER_AC_CNTACR_RVOFF | QCT_QTIMER_AC_CNTACR_RF= RQ | + QCT_QTIMER_AC_CNTACR_RPVCT | QCT_QTIMER_AC_CNTACR_RP= CT; + t->cntval =3D 0; + t->int_level =3D 0; + t->offset_ns =3D qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + timer_del(t->timer); + } +} + +static const Property qct_qtimer_properties[] =3D { + DEFINE_PROP_UINT32("freq", QCTQtimerState, freq, QTIMER_DEFAULT_FREQ_H= Z), + 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, 0x100= 0), + 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 =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + device_class_set_props(dc, qct_qtimer_properties); + dc->realize =3D qct_qtimer_realize; + dc->vmsd =3D &vmstate_qct_qtimer; + rc->phases.hold =3D qct_qtimer_reset_hold; +} + +/* QTimer interface implementation, backing HEX_SREG_TIMERLO/TIMERHI */ +static uint32_t qct_qtimer_get_timer_lo_impl(QctQtimerInterface *obj) +{ + QCTQtimerState *s =3D QCT_QTIMER(obj); + + return s->nr_frames > 0 ? extract64(hex_timer_now(&s->timer[0]), 0, 32) + : 0; +} + +static uint32_t qct_qtimer_get_timer_hi_impl(QctQtimerInterface *obj) +{ + QCTQtimerState *s =3D QCT_QTIMER(obj); + + return s->nr_frames > 0 ? extract64(hex_timer_now(&s->timer[0]), 32, 3= 2) + : 0; +} + +static void qct_qtimer_interface_class_init(ObjectClass *klass, + const void *data) +{ + QctQtimerInterfaceClass *k =3D QCT_QTIMER_INTERFACE_CLASS(klass); + + k->get_timer_lo =3D qct_qtimer_get_timer_lo_impl; + k->get_timer_hi =3D qct_qtimer_get_timer_hi_impl; +} + +static const TypeInfo qct_qtimer_interface_info =3D { + .name =3D TYPE_QCT_QTIMER_INTERFACE, + .parent =3D TYPE_INTERFACE, + .class_size =3D sizeof(QctQtimerInterfaceClass), + .class_init =3D qct_qtimer_interface_class_init, +}; + +static const TypeInfo qct_qtimer_info =3D { + .name =3D TYPE_QCT_QTIMER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(QCTQtimerState), + .class_init =3D qct_qtimer_class_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_QCT_QTIMER_INTERFACE }, + { } + }, +}; + +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) diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index b3d823ce2c3..e1b751a54a7 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -65,3 +65,6 @@ config STELLARIS_GPTM =20 config AVR_TIMER16 bool + +config HEX_QTIMER + bool diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 201b5d8316d..0e8326b0492 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -34,3 +34,5 @@ specific_ss.add(when: 'CONFIG_IBEX', if_true: files('ibex= _timer.c')) system_ss.add(when: 'CONFIG_SIFIVE_PWM', if_true: files('sifive_pwm.c')) =20 system_ss.add(when: 'CONFIG_AVR_TIMER16', if_true: files('avr_timer16.c')) + +specific_ss.add(when: 'CONFIG_HEX_QTIMER', if_true: files('qct-qtimer.c')) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 634ba1da27a..636310f8caa 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -128,3 +128,8 @@ imx_epit_get_freq(uint32_t freq) "ptimer frequency is %= u" imx_epit_read(const char *name, uint32_t value) "(%s) =3D 0x%08x" imx_epit_write(const char *name, uint64_t value) "(%s, value =3D 0x%08" PR= Ix64 ")" imx_epit_cmp(uint32_t sr) "sr was %d" + +# qct-qtimer.c +qtimer_interrupt(void) "qtimer interrupt line updated" +qtimer_read(uint64_t offset) "offset 0x%" PRIx64 +qtimer_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value = 0x%" PRIx64 --=20 2.34.1 From nobody Sat Jul 25 13:39:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=oss.qualcomm.com ARC-Seal: i=1; a=rsa-sha256; t=1784338447; cv=none; d=zohomail.com; s=zohoarc; b=CsEa+ZS0dNdn6FQ5TcdhkFs/TE9yQH301Rk8ZNIBa64U+6U4LODZx045+L+rR74m2yWcJLxUmf73PHYEi9zZ98enMjMJKiolOCKWq2aeJduUli4OuX3Xu8X2mwggQV22cZQAT9OKe5FC0tM2ZNJ+ceZk5v540ciGaJP53qMVRGI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784338447; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=6nGfhFmh5XbhzweIQF3S2reH1pEVxR5b4qBroD6mLqE=; b=jyHgEd+TOCLZt72xhJLqbRJzhJb8VdlW7oVO/WFp0SEb11TAU31QxVtpGUsJzXLZ3o0O7o9s00hwoeV9I/iukxZQO5SnVTbRmU6bp8PlWjXfJe1Ajzuxzqd4XGzh1hfOOvZID7hxu3KHSQ0EfQtE7o96CG9i8rc9u5GYGuUgewQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784338447665499.3239613322813; Fri, 17 Jul 2026 18:34:07 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wktvH-0005Xi-EX; Fri, 17 Jul 2026 21:32:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktv8-0005WN-7Z for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:50 -0400 Received: from mx0b-0031df01.pphosted.com ([205.220.180.131]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktv6-0005v7-ET for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:49 -0400 Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66HNEKDH3312502 for ; Sat, 18 Jul 2026 01:32:47 GMT Received: from mail-pj1-f71.google.com (mail-pj1-f71.google.com [209.85.216.71]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4ffhpfk9vv-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sat, 18 Jul 2026 01:32:47 +0000 (GMT) Received: by mail-pj1-f71.google.com with SMTP id 98e67ed59e1d1-38869800848so12631362a91.0 for ; Fri, 17 Jul 2026 18:32:46 -0700 (PDT) Received: from hu-bcain-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3142a1ddeb6sm13393494eec.20.2026.07.17.18.32.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jul 2026 18:32:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= 6nGfhFmh5XbhzweIQF3S2reH1pEVxR5b4qBroD6mLqE=; b=W6eVmVXM0Vz1/ueW bnNERfV5GpBeYKXaVtueACPciNfJVeTIztfbKeb9ln7J+RYvAqKiGcfjMU5gQm4H ID/7COkA/ceP1aOpGLqQnGt4HXvzZ2SqVjxMYtEw5JqTRVYlrO9VxVJXFCWUFGHl guSAPggYSpwgCWt3/rTRQSfw6dRBvo3Zd/T/sMf9o2deGHiiZKvNyEacWzZQ9lJR VdrIQvso4RPAZGAqjgHCOsp8idk9yNUTEc1++7eGDoda33GsWx40KorsTRpwTc32 JKGEvE0xWGlrHUHB0QKfEYoCkIbwS4D+IgNc2nDdLImP/MWeqAV3DzYZOW/hex3M ttrFYA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1784338366; x=1784943166; darn=nongnu.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=6nGfhFmh5XbhzweIQF3S2reH1pEVxR5b4qBroD6mLqE=; b=cy18p1zZS5FICzeiTuu1GaMX9XfSnSS2MupuU/ER3yu+/eSLLcv3UKTbpjnnohzoGe f10hjDAlXoPzL6eAnX+HAEoTVb2KRfieHQ5u7TLf05WgpUnzF2GKVzRW+WfAgw39vxKR YmRlCTDHlsnSuQ7SzNumu+altYhm8mO/sFq0agIa812HOMiPDFvYV6+3CHwrNZuyuMP1 TrHyob3P2lmYVFSD+ATzbAbYBPLa7Th7lTOvmNdwBv4+xsIw4LqdejZX2zgHbB1QCFnU z6SiTfysqIx+3RwSkpHYOJWb0r1JG9rLPnNS6KPEemjIs+QVd1OgkWA6oyDD0B1OuEq1 a1hg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784338366; x=1784943166; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=6nGfhFmh5XbhzweIQF3S2reH1pEVxR5b4qBroD6mLqE=; b=JMw+IkxNhMfQiUS2jSPKLeZO/ez4L1HGSCmjUkQ7IMfIXuM7+PO4v3pLkwVSRna96V k5GXcRBKJHJUhYD2QrwT60rtaOsEUA1ppK1H8Q3o07ekOGwCxVShywZ9SjWSD6Cz8hVD z89t1vZi7vsSWqOYPd9T9/HiGQ8sAxeOOgvFvTeCGLC0j+AvVgC6mqGNp5w3/I/EnmuI 1DwQTVi19I7Lyf3jlTLuQVC10QbkG5hDMK+Y1+cB3WKkkz9jts8r3qcmGot+UcK9CqYg rng1Np8yFYNQV8n+Z4AX1kt6uToAd9SCqVkoDzEqPT9HDqABgn9vqKghjW8cEUo3W/yG QubA== X-Gm-Message-State: AOJu0YwdjOPpyJ8Yct7CHZkV/64bLdbqFFhdL3K2HbY81aCbh4ZzQMXD cLpf5lFXvKXNuYWJv469rm9SAYJDmSTwz2Xf2VLuN3uBgoUGMUoznQyxPUTqqLYTnj7KGLkSLix sl0xCryOZaSwQ+DZxVv+4rWlmjQxtEBbMEqKyyailkEpv1Ag24DHfmk95L8qBh8vfMg== X-Gm-Gg: AfdE7cnBjNix2KfYZ80BeblselaZjiP7T+0UxA/T98mZO3b6+erdock9VhJMQvnjNmy 1BVgLABVYBOJMR9QZEL6ymVZyyJoynDiPkTEU3ksvSVBDSUQE2hw+ogo4zjvt3MeeHINEIaCAud 4momW+qwj0DkWhMWJEu8LRFAu25qhBG5ttf8gOSGtz0+pzNPuF5PHhn2hiCy6hHhKJ0amCUqxr7 B0cBeiOyl8TkLK6sYnzwZZFxB1KXi7SI5efbjqjFiu35Cf++UbTjgi8wS8p6dYVTj0XF1qW/9qe vz6q2Mo9Bdvh8bjQtlc3aM3kPF513Nc6qJvDTyWwufXiT8Dy8ybhrvh4xRiaIQl64A9hX/fOoVQ HOJsIF+RwZ3Yf92mexty7RIYS2pcJNlzCDXn/nj2An/dT0eQL X-Received: by 2002:a17:90b:3890:b0:37f:9ce1:736a with SMTP id 98e67ed59e1d1-38e4b56bc90mr5011801a91.32.1784338366001; Fri, 17 Jul 2026 18:32:46 -0700 (PDT) X-Received: by 2002:a17:90b:3890:b0:37f:9ce1:736a with SMTP id 98e67ed59e1d1-38e4b56bc90mr5011770a91.32.1784338365477; Fri, 17 Jul 2026 18:32:45 -0700 (PDT) From: Brian Cain To: qemu-devel@nongnu.org Cc: philmd@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, Paolo Bonzini , Laurent Vivier , Brian Cain , Fabiano Rosas , matheus.bernardino@oss.qualcomm.com Subject: [PATCH 2/3] hw/hexagon: connect qtimer device Date: Fri, 17 Jul 2026 18:32:40 -0700 Message-Id: <20260718013241.1550124-3-brian.cain@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> References: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE4MDAxMiBTYWx0ZWRfX7jWUcUSLQwn0 RuWCVfha+KkTNT7Rh1a+enpmaU7Qr1aymICWsMSicsuQp65yprKmw8n7rfuMRCTGGenzHzsZY/k eFYPXj8AOC7vJoa0xQPr/v+hYPxMp4A0hblLlkLAlQ6CtK7BeCNKCrmobtyBnVoKln/NesB8QkU H1Bd41DITMJageet8jD82dL6yMxHoCQIq1UMR+0KUz6U9zK4e7MybO2rfhM6R+ZsnzBZUCXzxuz AULbyeZJcgeACBQirdylYpC/+96l3RZN6UwoHcXSovwqHptjyZD4WMtFIq/tTivcyY6JShIpFVI Z5varW2mDrXiCKSZUEyvowK6/iG9FzTldgpZ4vu/aoeVhULl5SiCY33/mGD7+1zlzO3aTaTc04S iHIT7o0sm2gKflqZoRzXtsf3B8VIq9zISgTWZdz17zkdWNSUAsbASAOZwoCsQXlyE03gab/9oDh sQAUtL4ioSQa7VOJ5NQ== X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE4MDAxMiBTYWx0ZWRfX3Kw/wJvm6QNb eDzHeOSV7JtAKe3mqSNHQSjLcdHN4JAZ7W0LVo5/5OYHuQUaFRy/LlRyIadwvYWWGAJKN3Lb344 Xt211XKeof7s2pCdcqVKqS729G5MG38= X-Authority-Analysis: v=2.4 cv=YeWNIQRf c=1 sm=1 tr=0 ts=6a5ad7bf cx=c_pps a=UNFcQwm+pnOIJct1K4W+Mw==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=3WHJM1ZQz_JShphwDgj5:22 a=EUspDBNiAAAA:8 a=AoH4l7DP3JI8jjo4MQwA:9 a=QEXdDO2ut3YA:10 a=uKXjsCUrEbL0IQVhDsJ9:22 X-Proofpoint-GUID: 4-Dn6Mo6KCG0ASJWsMI9iavBZuilRmgM X-Proofpoint-ORIG-GUID: 4-Dn6Mo6KCG0ASJWsMI9iavBZuilRmgM X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-17_07,2026-07-17_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 bulkscore=0 suspectscore=0 priorityscore=1501 clxscore=1015 spamscore=0 lowpriorityscore=0 adultscore=0 phishscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607180012 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=205.220.180.131; envelope-from=brian.cain@oss.qualcomm.com; helo=mx0b-0031df01.pphosted.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @qualcomm.com) X-ZM-MESSAGEID: 1784338449835158500 Instantiate the QTimer device in both machine models, map its view region, connect its interrupt lines into l2vic, and link it to the globalreg device. Store the QTimer DeviceState pointer in the shared HexagonCommonMachineState. Signed-off-by: Brian Cain --- include/hw/hexagon/hexagon.h | 1 + include/hw/hexagon/hexagon_globalreg.h | 4 ++++ hw/hexagon/hexagon_dsp.c | 14 ++++++++++++++ hw/hexagon/hexagon_globalreg.c | 17 +++++++++++++++-- hw/hexagon/virt.c | 16 ++++++++++++++++ hw/hexagon/Kconfig | 1 + 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/hw/hexagon/hexagon.h b/include/hw/hexagon/hexagon.h index 6753ae32cde..3eea1e54ff2 100644 --- a/include/hw/hexagon/hexagon.h +++ b/include/hw/hexagon/hexagon.h @@ -157,6 +157,7 @@ struct HexagonCommonMachineState { MemoryRegion ram; MemoryRegion cfgtable_rom; DeviceState *l2vic_dev; + DeviceState *qtimer_dev; }; =20 #endif diff --git a/include/hw/hexagon/hexagon_globalreg.h b/include/hw/hexagon/he= xagon_globalreg.h index 397dc6854c9..07437dfabb1 100644 --- a/include/hw/hexagon/hexagon_globalreg.h +++ b/include/hw/hexagon/hexagon_globalreg.h @@ -11,6 +11,7 @@ #include "hw/core/qdev.h" #include "hw/core/sysbus.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "qom/object.h" #include "target/hexagon/cpu.h" =20 @@ -26,6 +27,9 @@ struct HexagonGlobalRegState { /* L2VIC interface used to back the VID/VID1 registers */ HexL2VicInterface *l2vic; =20 + /* QTimer interface used to back the TIMERLO/TIMERHI registers */ + QctQtimerInterface *qtimer; + /* Global performance cycle counter base */ uint64_t g_pcycle_base; =20 diff --git a/hw/hexagon/hexagon_dsp.c b/hw/hexagon/hexagon_dsp.c index 4cf88627c8f..21bb80ac27a 100644 --- a/hw/hexagon/hexagon_dsp.c +++ b/hw/hexagon/hexagon_dsp.c @@ -17,6 +17,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "hw/core/loader.h" #include "qapi/error.h" #include "qemu/error-report.h" @@ -141,6 +142,17 @@ static void hexagon_common_init(MachineState *machine,= Rev_t rev, sysbus_mmio_map(SYS_BUS_DEVICE(hms->l2vic_dev), 1, m_cfg->cfgtable.fastl2vic_base << 16); =20 + hms->qtimer_dev =3D qdev_new(TYPE_QCT_QTIMER); + object_property_add_child(OBJECT(machine), "qtimer", + OBJECT(hms->qtimer_dev)); + qdev_prop_set_uint32(hms->qtimer_dev, "nr_frames", 3); + sysbus_realize_and_unref(SYS_BUS_DEVICE(hms->qtimer_dev), &error_fatal= ); + sysbus_mmio_map(SYS_BUS_DEVICE(hms->qtimer_dev), 1, m_cfg->qtmr_region= ); + sysbus_connect_irq(SYS_BUS_DEVICE(hms->qtimer_dev), 0, + qdev_get_gpio_in(hms->l2vic_dev, 3)); + sysbus_connect_irq(SYS_BUS_DEVICE(hms->qtimer_dev), 1, + qdev_get_gpio_in(hms->l2vic_dev, 4)); + glob_regs_dev =3D qdev_new(TYPE_HEXAGON_GLOBALREG); object_property_add_child(OBJECT(machine), "global-regs", OBJECT(glob_regs_dev)); @@ -148,6 +160,8 @@ static void hexagon_common_init(MachineState *machine, = Rev_t rev, qdev_prop_set_uint32(glob_regs_dev, "dsp-rev", rev); object_property_set_link(OBJECT(glob_regs_dev), "l2vic", OBJECT(hms->l2vic_dev), &error_fatal); + object_property_set_link(OBJECT(glob_regs_dev), "qtimer", + OBJECT(hms->qtimer_dev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(glob_regs_dev), &error_fatal); =20 tlb_dev =3D qdev_new(TYPE_HEXAGON_TLB); diff --git a/hw/hexagon/hexagon_globalreg.c b/hw/hexagon/hexagon_globalreg.c index 3d0d6f9516c..0353d89f87b 100644 --- a/hw/hexagon/hexagon_globalreg.c +++ b/hw/hexagon/hexagon_globalreg.c @@ -141,15 +141,26 @@ static inline bool is_vid_reg(uint32_t reg) return reg =3D=3D HEX_SREG_VID || reg =3D=3D HEX_SREG_VID1; } =20 +static inline bool is_timer_reg(uint32_t reg) +{ + return reg =3D=3D HEX_SREG_TIMERLO || reg =3D=3D HEX_SREG_TIMERHI; +} + /* - * HEX_SREG_VID/VID1 are backed by the L2VIC's VID group registers - * rather than the plain regs[] array, when an L2VIC is wired up. + * HEX_SREG_VID/VID1 are backed by the L2VIC's VID group registers, and + * HEX_SREG_TIMERLO/TIMERHI are backed by the QTimer's live counter, + * rather than the plain regs[] array, when those devices are wired up. */ static uint32_t get_reg_value(HexagonGlobalRegState *s, uint32_t reg) { if (is_vid_reg(reg) && s->l2vic) { return l2vic_read_vid(s->l2vic, reg =3D=3D HEX_SREG_VID ? 0 : 1); } + if (is_timer_reg(reg) && s->qtimer) { + return reg =3D=3D HEX_SREG_TIMERLO ? + qct_qtimer_get_timer_lo(s->qtimer) : + qct_qtimer_get_timer_hi(s->qtimer); + } return s->regs[reg]; } =20 @@ -306,6 +317,8 @@ static const VMStateDescription vmstate_hexagon_globalr= eg =3D { static const Property hexagon_globalreg_properties[] =3D { DEFINE_PROP_LINK("l2vic", HexagonGlobalRegState, l2vic, TYPE_HEX_L2VIC_INTERFACE, HexL2VicInterface *), + DEFINE_PROP_LINK("qtimer", HexagonGlobalRegState, qtimer, + TYPE_QCT_QTIMER_INTERFACE, QctQtimerInterface *), DEFINE_PROP_UINT32("boot-evb", HexagonGlobalRegState, boot_evb, 0x0), DEFINE_PROP_UINT64("config-table-addr", HexagonGlobalRegState, config_table_addr, 0xffffffffULL), diff --git a/hw/hexagon/virt.c b/hw/hexagon/virt.c index 2256d3d53a5..7e32765d1cc 100644 --- a/hw/hexagon/virt.c +++ b/hw/hexagon/virt.c @@ -16,6 +16,7 @@ #include "hw/hexagon/hexagon_globalreg.h" #include "hw/hexagon/hexagon_tlb.h" #include "hw/intc/hex-l2vic.h" +#include "hw/timer/qct-qtimer.h" #include "hw/core/loader.h" #include "hw/core/qdev-properties.h" #include "hw/core/qdev-clock.h" @@ -279,12 +280,27 @@ static void virt_init(MachineState *ms) sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.l2vic_dev), 1, m_cfg->cfgtable.fastl2vic_base << 16); =20 + vms->parent_obj.qtimer_dev =3D qdev_new(TYPE_QCT_QTIMER); + object_property_add_child(OBJECT(ms), "qtimer", + OBJECT(vms->parent_obj.qtimer_dev)); + qdev_prop_set_uint32(vms->parent_obj.qtimer_dev, "nr_frames", 2); + sysbus_realize_and_unref(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), + &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 1, + m_cfg->qtmr_region); + sysbus_connect_irq(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 0, + qdev_get_gpio_in(vms->parent_obj.l2vic_dev, 3)); + sysbus_connect_irq(SYS_BUS_DEVICE(vms->parent_obj.qtimer_dev), 1, + qdev_get_gpio_in(vms->parent_obj.l2vic_dev, 4)); + gsregs_dev =3D qdev_new(TYPE_HEXAGON_GLOBALREG); object_property_add_child(OBJECT(ms), "global-regs", OBJECT(gsregs_dev= )); qdev_prop_set_uint64(gsregs_dev, "config-table-addr", m_cfg->cfgbase); qdev_prop_set_uint32(gsregs_dev, "dsp-rev", v68_rev); object_property_set_link(OBJECT(gsregs_dev), "l2vic", OBJECT(vms->parent_obj.l2vic_dev), &error_fat= al); + object_property_set_link(OBJECT(gsregs_dev), "qtimer", + OBJECT(vms->parent_obj.qtimer_dev), &error_fa= tal); sysbus_realize_and_unref(SYS_BUS_DEVICE(gsregs_dev), &error_fatal); =20 tlb_dev =3D qdev_new(TYPE_HEXAGON_TLB); diff --git a/hw/hexagon/Kconfig b/hw/hexagon/Kconfig index 191c6c5d65c..56cd5b15c55 100644 --- a/hw/hexagon/Kconfig +++ b/hw/hexagon/Kconfig @@ -3,6 +3,7 @@ config HEX_DSP default y depends on HEXAGON select HEX_L2VIC + select HEX_QTIMER =20 config HEX_VIRT bool --=20 2.34.1 From nobody Sat Jul 25 13:39:50 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=oss.qualcomm.com ARC-Seal: i=1; a=rsa-sha256; t=1784338413; cv=none; d=zohomail.com; s=zohoarc; b=ZqwRzYAalp71H4tfmlwN7jtgJKfTxRubAwAszm6vbISO9pS/Movoo5wKKel/I+e+xqNfhpeTV3AKDJ2K29NzAPoa93C4rKywM/0XOBR4mF3q6pyTw9oRhS/X9Lm6Q0ehQqQM1M4Ab39P0e122F2db94/8bc6yD7KF0R3i4MMraA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1784338413; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Gmfz0Zq7X/l3XCiCkd9dBZlwJluTzSzNkqVMRHz7cr8=; b=lnKdWrOceHW2zS2pHEGVQkgaKXn7+zEqaT+5o2jUEhxE3UkyWdIF2AP76Ik77iP1L4290mzKlST4GXUuUjQXfT/LHYDsrTJv+FhvhxEnUXwtuUiNt0dObZl506krUeft+DF6GTRcvctGOH/3ZVXs7DRNs0r57NlJuzGSnjLyp6A= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1784338413687905.473612719028; Fri, 17 Jul 2026 18:33:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wktvG-0005XQ-Hs; Fri, 17 Jul 2026 21:32:58 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktv9-0005Wa-Aq for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:52 -0400 Received: from mx0a-0031df01.pphosted.com ([205.220.168.131]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wktv7-0005vD-7D for qemu-devel@nongnu.org; Fri, 17 Jul 2026 21:32:51 -0400 Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 66I0hb7V322618 for ; Sat, 18 Jul 2026 01:32:48 GMT Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4ffy6f032k-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sat, 18 Jul 2026 01:32:47 +0000 (GMT) Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-380b630c505so10318600a91.1 for ; Fri, 17 Jul 2026 18:32:47 -0700 (PDT) Received: from hu-bcain-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3142a1ddeb6sm13393494eec.20.2026.07.17.18.32.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jul 2026 18:32:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= Gmfz0Zq7X/l3XCiCkd9dBZlwJluTzSzNkqVMRHz7cr8=; b=bdbslcMn14t/aWLG Y6y7dtdkmdWcV/AAgjZ6l5inVWBBhONUYqI719VVtq/sGtmrUVJDzfJ1WoPP92Os hF7UPkvqiWRFsj4QPTEIsHaf14o1xGZML8M3WnDC4rZBWlgBXVRbhBKb1hebuDkj gKoWEJ/9PwbRN06pNo8aBt1nADZ/Q7uXS+KIL26kAw79vLrayxfct1qzQhoSaT5a OJyKbmg71WRqo4tssHID847CLmQFv8uIp3OB5MYvautK8Wh+oZGsbOGe/FTxhyW5 dpIKMhhAN5YUgpu8shOEf33fzJ6QYNCxlC+c24Yl12NJ6ItSCKpPcvPhgnIPrNBS jVTwwQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1784338367; x=1784943167; darn=nongnu.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=Gmfz0Zq7X/l3XCiCkd9dBZlwJluTzSzNkqVMRHz7cr8=; b=ENRfgSgTzTaqUohMlLiunzr1fkaX2hhofVUK2yh0eTF9cMD09a2LszOcJLdKU20Q90 32jDhmGklWclMoGW4n7n2PMw0xZ3URcXBAr3p3qqqsfLHRTvbTkiAFDk5CqRkrh+2jON 7zvtjfDIotLCEPSRxYbHS+eRFu9Q4DckHXtn8ix0nHA4lxIKUR8/51ohWZu0xr+nniMx +mhBIMjFMt8WHmI7VFLaYZCVNJ/Wb6Y0T/wK/xeKbBd9QUxUkhfB7InwqGhK2RxW2W4j aIi2PEMvrPPj1oLTrOuUzKZZ364wtoSYwlFULx+CenYCUV+RuR3iGY7eBvuDW7wxKxa1 Gczg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784338367; x=1784943167; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Gmfz0Zq7X/l3XCiCkd9dBZlwJluTzSzNkqVMRHz7cr8=; b=hCaVqSyifKacLuys5QsY9l5iQ0P2tdekOB5BdAVXJVrbBvHVV19vSJU4jBbOsQelAv lzfYFg+JHYl2Efw9jGTQmO2leGeaZf5GTo25Egq1a8RMMNxrcNwdr9Wr/zncL/j+18Rl /u7Ts1qk/wiH6jHztCh9whExBXZDbor73aBFf+8ANznw7DQCvDTYTMPG08dAdkjeihM8 DP7boMLyH/hlTjZvjQ3XKmxSvlR063yaayORv8JLFu1Dk0y3QA3BJwV9Kt5k86vI8Uly 2xhl6bHWHC5rNxZIgf0OfFToCl0/P6QbnJ2wy6PwXckh5T9uXNjujpqvENWg61N69uL5 9bPw== X-Gm-Message-State: AOJu0YwwlQDWFqjvwHOP5NWpAJ/YL9+SiyhTIjtwYD8ad+tqTRtKJ50C M2Sp361Rhf7pdM0ODcqH5E20fKEa3bjKBPxxkNV+MjWqNxRUglSQSs/KihYfFrwaYRVAWiADGYJ +LHYxurXi0bGtDGyfym09zkjGtMBJ+6P/E4wtbLaROCh0iaChsFB3aXlMk0InyBadfw== X-Gm-Gg: AfdE7ckPd4rte4GIPChx1Qa8g4CwVQYd7yH3EOzrHGt71KkHtgO5VdUr7NVLnjzqRZ1 DZtbSfPsucYX8Zcisas9fKH8f/LhPhuNggIAUkfDZ+wQ0UvN+PXDRv1tcdtg0gBcXp8FaUf4Z+U 0iF5GQyo4lFws1oW7BwslGPw9ngKRalEEUziZS/pccX2cwuEDLE6BZhk61bT2mmEHWwVSv6+k6v hBsabpKTGdQKvV+4Xelown5Gq1DCwPw9gXbijYdzEtIbkGQdBrwjW1pyo45G8CdHwh90jMFPgYN c2MHHudk5UFcEtrwiMh2Ckkp36pg5w0yS2PyLJGWmir36X8lV2/5Ff39QbDFa+dMyC0S5g8E68j 4C29JpoeCiREODTqjnnj1vk1LH+uB3cn6y+eBdrTp7VgpGZNR X-Received: by 2002:a17:90a:dfcc:b0:366:3517:1aa2 with SMTP id 98e67ed59e1d1-38e4b24d8ddmr5277662a91.0.1784338367063; Fri, 17 Jul 2026 18:32:47 -0700 (PDT) X-Received: by 2002:a17:90a:dfcc:b0:366:3517:1aa2 with SMTP id 98e67ed59e1d1-38e4b24d8ddmr5277641a91.0.1784338366615; Fri, 17 Jul 2026 18:32:46 -0700 (PDT) From: Brian Cain To: qemu-devel@nongnu.org Cc: philmd@oss.qualcomm.com, pierrick.bouvier@oss.qualcomm.com, Paolo Bonzini , Laurent Vivier , Brian Cain , Fabiano Rosas , matheus.bernardino@oss.qualcomm.com Subject: [PATCH 3/3] tests/qtest: add qct-qtimer qtest Date: Fri, 17 Jul 2026 18:32:41 -0700 Message-Id: <20260718013241.1550124-4-brian.cain@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> References: <20260718013241.1550124-1-brian.cain@oss.qualcomm.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Proofpoint-ORIG-GUID: 7NbGX_8Y5iLBhTncBgGrJYG2uZ4RVGxR X-Proofpoint-GUID: 7NbGX_8Y5iLBhTncBgGrJYG2uZ4RVGxR X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNzE4MDAxMSBTYWx0ZWRfXyBQdZw+gq5jb KxsMyvpTAGfhhZQATCYRsmKDHUTjjc/J1ZzyqLznHX4AyAcl5AoOTdLtDqhQBRLHAOPh4lqthB0 X53pZIxaL7Z+BjkAs/iDYLTbVh6PgSbxaNBHI+vjindK3unfFueA4MLsuBYqAeV30YqEj1JmW4Z +oYLKKSOcxxeKZfYGceFewmCjYxxS4F4DGN3rQ85YGpFmgigXG6irCZObeBDuCMxeA1lbmGPBuO DikOOsk2a5AXjTT0kVenkzEXWSdm1rRVPwW/reYg9c678UmzWjhwWd6rYBSWiGW0kUxCiMI9QTT h7z9kXHEkQF9UBx7KuoVxU5ZjZooHunHpl0ey/U/Y8qEW7Sth9XPPoez35fP29huL1FPdf4SBYf YpNL0X7h5aWS3fLO2S0LbvP4lLOh+X/8mcMomOTllOIHMojMWBgpnm5Ovj8UCkW/2a43OyLBbHX 2eMKxfYXDXxj5z1sg0Q== X-Proofpoint-Spam-Info: AW1haW4tMjYwNzE4MDAxMSBTYWx0ZWRfX5O65FVrXJB0d eGhTCWmuvesKS7upPxn2u1dGKivy0GXbpaq53GeRq1jxXIwlBUGMzB9sEYgXDLoccFmPwI+zfz+ VutNq5w+5STWdr475uSZXdElHEhUCFc= X-Authority-Analysis: v=2.4 cv=BIODalQG c=1 sm=1 tr=0 ts=6a5ad7bf cx=c_pps a=vVfyC5vLCtgYJKYeQD43oA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=RAioF0-LDSMA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=EUspDBNiAAAA:8 a=_lenfoqx_2fFCmtxMucA:9 a=QEXdDO2ut3YA:10 a=rl5im9kqc5Lf4LNbBjHf:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-07-17_07,2026-07-17_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 impostorscore=0 bulkscore=0 phishscore=0 adultscore=0 malwarescore=0 suspectscore=0 clxscore=1015 lowpriorityscore=0 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2607180011 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=205.220.168.131; envelope-from=brian.cain@oss.qualcomm.com; helo=mx0a-0031df01.pphosted.com X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @qualcomm.com) X-ZM-MESSAGEID: 1784338417146158500 Add a qtest exercising the QCT QTimer's register access, view-region frame addressing, and one-shot timer firing behavior. Signed-off-by: Brian Cain --- MAINTAINERS | 1 + tests/qtest/qct-qtimer-test.c | 213 ++++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 +- 3 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/qct-qtimer-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 2c73705c727..94977c3be77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -255,6 +255,7 @@ 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 +F: tests/qtest/qct-qtimer-test.c X: target/hexagon/idef-parser/ X: target/hexagon/gen_idef_parser_funcs.py F: linux-user/hexagon/ diff --git a/tests/qtest/qct-qtimer-test.c b/tests/qtest/qct-qtimer-test.c new file mode 100644 index 00000000000..146d98126ac --- /dev/null +++ b/tests/qtest/qct-qtimer-test.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QTest testcase for the QCT QTimer + */ + +#include "qemu/osdep.h" +#include "libqtest-single.h" +#include "hw/timer/qct-qtimer.h" +#include "qemu/bitops.h" + +#define QTIMER_DEFAULT_FREQ_HZ 19200000ULL +#define QTIMER_VIEW_BASE 0xfc921000 + +#define TIMER_TEST_OFFSET 1000 +/* TIMER_TEST_OFFSET ticks expressed in nanoseconds of QEMU_CLOCK_VIRTUAL = */ +#define TIMER_TEST_NS \ + ((TIMER_TEST_OFFSET * 1000000000ULL) / QTIMER_DEFAULT_FREQ_HZ) + +static uint32_t qtimer_read32(uint64_t base, uint32_t offset) +{ + return readl(base + offset); +} + +static void qtimer_write32(uint64_t base, uint32_t offset, uint32_t value) +{ + writel(base + offset, value); +} + +static uint64_t qtimer_read64(uint64_t base, uint32_t offset) +{ + uint32_t lo =3D qtimer_read32(base, offset); + uint32_t hi =3D qtimer_read32(base, offset + 4); + + return ((uint64_t)hi << 32) | lo; +} + +static void qtimer_write64(uint64_t base, uint32_t offset, uint64_t value) +{ + qtimer_write32(base, offset, extract64(value, 0, 32)); + qtimer_write32(base, offset + 4, extract64(value, 32, 32)); +} + +/* Test basic device presence and register access */ +static void test_qtimer_basic_access(void) +{ + uint32_t val; + + val =3D qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, =3D=3D, QTIMER_DEFAULT_FREQ_HZ); +} + +/* Test multiple timer frames */ +static void test_qtimer_multiple_frames(void) +{ + uint32_t val; + uint64_t frame0_base =3D QTIMER_VIEW_BASE; + uint64_t frame1_base =3D QTIMER_VIEW_BASE + 0x1000; + + val =3D qtimer_read32(frame0_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, =3D=3D, QTIMER_DEFAULT_FREQ_HZ); + + val =3D qtimer_read32(frame1_base, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(val, =3D=3D, QTIMER_DEFAULT_FREQ_HZ); +} + +/* Test that registers exist and can be accessed */ +static void test_qtimer_register_reads(void) +{ + qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNT_FREQ); + qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO); + qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_TVAL); +} + +/* Test timer control and value registers */ +static void test_qtimer_control_registers(void) +{ + uint32_t ctl_val; + uint64_t cval_before, cval_after; + + cval_before =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + + qtimer_write32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_TVAL, 1000); + + qtimer_write32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL, 1); + ctl_val =3D qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + if (ctl_val & 1) { + g_assert_cmpuint(ctl_val & 1, =3D=3D, 1); + } + + /* CVAL should be greater than before since we set TVAL */ + cval_after =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO= ); + g_assert_cmpuint(cval_after, >, cval_before); + + qtimer_write32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL, 0); + ctl_val =3D qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(ctl_val & 1, =3D=3D, 0); +} + +/* Test CVAL register direct access */ +static void test_qtimer_cval_access(void) +{ + uint64_t current_time, test_cval, read_cval; + + current_time =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + test_cval =3D current_time + 10000; + + qtimer_write64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO, test_cval); + read_cval =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(read_cval, =3D=3D, test_cval); +} + +/* Test counter progression */ +static void test_qtimer_counter_progression(void) +{ + uint32_t freq; + uint64_t count1, count2; + + /* + * In qtest mode the virtual clock does not advance on its own, so + * reading the counter twice must give the same value. + */ + count1 =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + count2 =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(count2, =3D=3D, count1); + + freq =3D qtimer_read32(QTIMER_VIEW_BASE, QCT_QTIMER_CNT_FREQ); + g_assert_cmpuint(freq, =3D=3D, QTIMER_DEFAULT_FREQ_HZ); +} + +/* Test timer behavior with clock control */ +static void test_qtimer_timer_behavior(void) +{ + uint64_t current_count, target_count, read_cval, new_count; + uint64_t ctl_val, count_after_disable; + + current_count =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO= ); + + target_count =3D current_count + TIMER_TEST_OFFSET; + qtimer_write64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO, target_count= ); + + read_cval =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CVAL_LO); + g_assert_cmpuint(read_cval, =3D=3D, target_count); + + qtimer_write32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL, 1); + + ctl_val =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + /* EN set, IMASK clear, ISTAT not yet pending */ + g_assert_cmpuint(ctl_val, =3D=3D, 0x1); + + /* Step forward but not past the target */ + qtest_clock_step(global_qtest, TIMER_TEST_NS / 2); + new_count =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(new_count, >=3D, current_count); + + /* Step past the target */ + qtest_clock_step(global_qtest, TIMER_TEST_NS); + new_count =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(new_count, >=3D, target_count); + + qtimer_write32(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL, 0); + + ctl_val =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + /* EN cleared, ISTAT set since new_count >=3D target_count */ + g_assert_cmpuint(ctl_val, =3D=3D, 0x4); + + /* + * CNTPCT runs independently of CNTP_CTL.EN: only the compare/IRQ + * logic is gated by EN, so the counter must keep advancing. + */ + qtest_clock_step(global_qtest, TIMER_TEST_NS / 2); + count_after_disable =3D qtimer_read64(QTIMER_VIEW_BASE, + QCT_QTIMER_CNTPCT_LO); + g_assert_cmpuint(count_after_disable, >, new_count); + + /* ISTAT remains set while CNTPCT >=3D CVAL, even with EN=3D0 */ + ctl_val =3D qtimer_read64(QTIMER_VIEW_BASE, QCT_QTIMER_CNTP_CTL); + g_assert_cmpuint(ctl_val, =3D=3D, 0x4); +} + +static void test_qtimer_on_machine(gconstpointer data) +{ + const char *machine =3D (const char *)data; + g_autofree char *args =3D g_strdup_printf( + "-machine %s -global qct-qtimer.freq-scale=3D1", machine); + + qtest_start(args); + + test_qtimer_basic_access(); + test_qtimer_multiple_frames(); + test_qtimer_register_reads(); + test_qtimer_control_registers(); + test_qtimer_cval_access(); + test_qtimer_counter_progression(); + test_qtimer_timer_behavior(); + + qtest_end(); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_data_func("/qct-qtimer/virt/all-tests", "virt", + test_qtimer_on_machine); + qtest_add_data_func("/qct-qtimer/V66G_1024/all-tests", "V66G_1024", + test_qtimer_on_machine); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index a76863c7dd6..651246b2ebb 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -299,7 +299,7 @@ qtests_riscv64 =3D ['riscv-csr-test'] + \ ['iommu-riscv-test'] : []) + \ (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) =20 -qtests_hexagon =3D ['boot-serial-test', 'l2vic-test'] +qtests_hexagon =3D ['boot-serial-test', 'l2vic-test', 'qct-qtimer-test'] =20 qos_test_ss =3D ss.source_set() qos_test_ss.add( --=20 2.34.1