From nobody Fri Aug 28 00:12:36 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1786628312; cv=none; d=zohomail.com; s=zohoarc; b=XR66v+ewJW+fgSCXzNd5ql9p5GjXq+7rBEhvO1I1jP9QFml1CsHk6ei9KYQOBGv2mk5j/Et1Ve5OOF/Qmin8RpWSDUs89sZuQuwE+JJjXklDZtnOaDrIcrGrEkDz1R/N5+LrjAd0Z0F7BX1E6t6Sw7A3ZJa0PunuApjhCfDroqI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786628312; h=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=UOxWjh1VbJP+voQHQuYFBnTFHTsWZfsA6DkNnXcCLlk=; b=fDDunqC//xiVD53JqMR9j3Ij6CtvjCpqxvGaSBPkHbAHI/QdIBNGr+3Rig2SCy+09ZzXQH7Wo9xyJYA/CI7bpvp4MW5kT4XGgDhdMaUKV07ozlf9Ra7aV7ljVKI3KwkteOwUN5lO8R3jmHH/OzUtAi2P20L3eW3PSkpHHWEu2YM= 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=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1786628312591116.31748572020365; Thu, 13 Aug 2026 06:38:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wuVcZ-0005op-C6; Thu, 13 Aug 2026 09:37:23 -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 1wuVcX-0005oQ-Nv for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:21 -0400 Received: from mail-pg1-x52c.google.com ([2607:f8b0:4864:20::52c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wuVcV-0005Ul-71 for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:21 -0400 Received: by mail-pg1-x52c.google.com with SMTP id 41be03b00d2f7-cbb8b54fcf8so1941501a12.0 for ; Thu, 13 Aug 2026 06:37:18 -0700 (PDT) Received: from DESKTOP-DFGP8OG ([2409:8a55:ad2:6951::258]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-cbef6849625sm1078901a12.1.2026.08.13.06.37.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 06:37:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786628238; x=1787233038; darn=nongnu.org; h=content-transfer-encoding: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=UOxWjh1VbJP+voQHQuYFBnTFHTsWZfsA6DkNnXcCLlk=; b=sP+GEpCsnC/YqQqRNEE4YvtSJldIvDn7aLkqLN+0Apwvs932DnR5WMG1biZQ0EDYbU FLL7nAKFQ/IgvHhkWbWJPm99SWXVDWDL7r/CcBpCCLOF3xmAyxjf/IRf5kopIaqhtJxz UghTD3nwYc353hhCtfp4qlDCVzvH5c1Sy/YXzdLhde6vf3ml0yERJkexqCymm0xjz/Op SqFTqgd2Bv76Gf/DXwYOf/45TnPTay740n+UcgfVM6RDLy9kAUCdDQtCjxEziiGUliLs Loi7ytPUJF9G+Si6zWorIxyust1Pa8qsmqaN+kVTqx+kMBXWHOpYY77Bnzdd/lpofWjV p/2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786628238; x=1787233038; h=content-transfer-encoding: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=UOxWjh1VbJP+voQHQuYFBnTFHTsWZfsA6DkNnXcCLlk=; b=KFsQ0hLJdHri9265R1RSs2psOe04MR14VBMXmwKnezqQmv0CvD5z35cE0Plez+CN48 Xa+nTX+fUgH92XKypHDhFS0yAT6Xiipurr7jWgfCO3/oCo9lt7fUxUsm0Y278/cm6Wl5 vqILnn8vZ5luDe3UEYP7bqT+TXLjceezIH0XnpdBka2neXNuxJFDOVz+c2K0I2yM5KHF i1afxmUEsu9w/vZbnpaKF5BK37lC1GBU3P7u+QeuSUwm399pAcJXlpA883d+MVjVrZqC Iavz8Mn0r/H0hqKMn4cIDkzgRvU4HUk9F9bePuIK7ZEe+Ry2Y0HW1H8XIHX2vlJnY8l0 ifXA== X-Gm-Message-State: AOJu0YxKrHFFs8DvfmzJWyQKQmAjULZ9mVAxqD6KUiUeXFhrm9E05+fM Dl2WrNBjPwuMD6ml2dMIFiuIKmSKoPfusiYtdtGT4Dcm9ZWBcGyJ3Q68YO3PVLtZWvk= X-Gm-Gg: AR+sD11Elq8JfAhgsyPlInOc0IPfNDhV7ZR1EdcDcp1124fk7kRreMy1HeNlAEzrcVy PZEgNyyJQOo4LgaPfwjMlONOgoc5xqhPW0h7cbIhKL5uYBnTcb9T60wtaLLTtAuUmLcqQLF4Z9z 1ZTZdAEXitNFl3efnE4dV20SdCu/d7UteSs5dUQaoXvnOayref/MlaTv1JMQVXG4IO9iZN22Oyt tqq3BCX7FKcHohmcLZcFSXjii/yOR/U5mSQEeMudrCdObhK0+7ZAKb6/FJdtaMt67hBHd68YwJf SjELZLoqYCxhLMKDv67E0MkGdz3XjhEIjUnaJJKSkzcJtJW8E2RxZ9UBMZt/v2GtWd3oOmn89QB WV1ki71GMCfE4JBHmiPd8Oo3T1ik1tAPkYGs2nNYvY5OBmcBQnvCX4OfuQIyE6leVq5AhSdjben maHOgZCWgSFpr2rYGSBBry3I38fVyYxZSfF/CcHoTQDuRGyeng5RSCsCnGg9g= X-Received: by 2002:a05:6a21:a38d:b0:3c8:f98f:475b with SMTP id adf61e73a8af0-3cc5539ee7amr8292980637.19.1786628237713; Thu, 13 Aug 2026 06:37:17 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, alistair.francis@wdc.com, palmer@dabbelt.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, bmeng.cn@gmail.com, philmd@oss.qualcomm.com, pbonzini@redhat.com, lvivier@redhat.com, farosas@suse.de, caojunze424@gmail.com, raoyi Subject: [PATCH v4 1/3] hw/timer: add DesignWare APB timer model Date: Thu, 13 Aug 2026 21:36:41 +0800 Message-ID: <20260813133643.20380-2-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813133643.20380-1-rao232328@gmail.com> References: <20260813133643.20380-1-rao232328@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::52c; envelope-from=rao232328@gmail.com; helo=mail-pg1-x52c.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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 @gmail.com) X-ZM-MESSAGEID: 1786628315364158500 Content-Type: text/plain; charset="utf-8" Add generic DesignWare APB timer device model. The number of timer channels is configurable via the num-timers property. Add timer files to MAINTAINERS. Signed-off-by: raoyi Reviewed-by: Bin Meng --- MAINTAINERS | 2 + hw/timer/Kconfig | 4 + hw/timer/dw-apb-timer.c | 376 ++++++++++++++++++++++++++++++++ hw/timer/meson.build | 1 + hw/timer/trace-events | 8 + include/hw/timer/dw-apb-timer.h | 40 ++++ 6 files changed, 431 insertions(+) create mode 100644 hw/timer/dw-apb-timer.c create mode 100644 include/hw/timer/dw-apb-timer.h diff --git a/MAINTAINERS b/MAINTAINERS index 6171cc7494..cf689433ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1826,8 +1826,10 @@ S: Maintained F: docs/system/riscv/k230.rst F: hw/riscv/k230.c F: hw/watchdog/k230_wdt.c +F: hw/timer/dw-apb-timer.c F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h +F: include/hw/timer/dw-apb-timer.h F: tests/qtest/k230-wdt-test.c =20 RX Machines diff --git a/hw/timer/Kconfig b/hw/timer/Kconfig index b3d823ce2c..b533cf1ba9 100644 --- a/hw/timer/Kconfig +++ b/hw/timer/Kconfig @@ -65,3 +65,7 @@ config STELLARIS_GPTM =20 config AVR_TIMER16 bool + +config DW_APB_TIMER + bool + select PTIMER diff --git a/hw/timer/dw-apb-timer.c b/hw/timer/dw-apb-timer.c new file mode 100644 index 0000000000..0b994e1570 --- /dev/null +++ b/hw/timer/dw-apb-timer.c @@ -0,0 +1,376 @@ +/* + * Synopsys DesignWare APB timer + * + * Copyright (c) 2026 raoyi + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/bitops.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "migration/vmstate.h" +#include "hw/core/ptimer.h" +#include "hw/core/qdev-clock.h" +#include "hw/core/sysbus.h" +#include "hw/core/qdev-properties.h" +#include "hw/timer/dw-apb-timer.h" +#include "trace.h" + +#define DW_APB_TIMER_STRIDE 0x14 +#define DW_APB_TIMER_MMIO_SIZE 0x100 + +/* Per-timer register offsets */ +#define DW_APB_TIMER_N_LOAD_COUNT 0x00 +#define DW_APB_TIMER_N_CURRENT_VALUE 0x04 +#define DW_APB_TIMER_N_CONTROL 0x08 +#define DW_APB_TIMER_N_EOI 0x0c +#define DW_APB_TIMER_N_INT_STATUS 0x10 +/* Global register offsets */ +#define DW_APB_TIMER_INT_STATUS 0xa0 +#define DW_APB_TIMER_EOI 0xa4 +#define DW_APB_TIMER_RAW_INT_STATUS 0xa8 +#define DW_APB_TIMER_COMP_VERSION 0xac + +/* Control register bits */ +#define DW_APB_TIMER_CONTROL_ENABLE BIT(0) +/* 1: periodic, 0: free running. */ +#define DW_APB_TIMER_CONTROL_MODE_PERIODIC BIT(1) +#define DW_APB_TIMER_CONTROL_INT BIT(2) +#define DW_APB_TIMER_CONTROL_RW_MASK 0x7 + +/* + * Component version of the DW_apb_timers IP, fixed in silicon. + * Decodes as the ASCII string "211*" (2.11a series); the model reports + * the version integrated in K230. Linux does not read this register. + */ +#define DW_APB_TIMER_COMP_VERSION_VAL 0x3231312A + +static void dw_apb_timer_update_irq(DWAPBTimerChannel *t) +{ + qemu_set_irq(t->irq, t->int_status && + !(t->control & DW_APB_TIMER_CONTROL_INT)); +} + +static void dw_apb_timer_clk_update(void *opaque, ClockEvent event) +{ + DWAPBTimerChannel *t =3D opaque; + + if (!t->ptimer) { + return; + } + ptimer_transaction_begin(t->ptimer); + ptimer_set_period_from_clock(t->ptimer, t->clk, 1); + ptimer_transaction_commit(t->ptimer); +} + +static void dw_apb_timer_enable(DWAPBTimerChannel *t) +{ + trace_dw_apb_timer_enable(t->id, t->load); + + ptimer_transaction_begin(t->ptimer); + ptimer_set_limit(t->ptimer, t->load ? t->load : 1, 1); + ptimer_run(t->ptimer, 1); + ptimer_transaction_commit(t->ptimer); +} + +static void dw_apb_timer_disable(DWAPBTimerChannel *t) +{ + trace_dw_apb_timer_disable(t->id); + + ptimer_transaction_begin(t->ptimer); + ptimer_stop(t->ptimer); + ptimer_transaction_commit(t->ptimer); + + t->int_status =3D 0; + dw_apb_timer_update_irq(t); +} + +static void dw_apb_timer_tick(void *opaque) +{ + DWAPBTimerChannel *t =3D opaque; + uint32_t reload; + + trace_dw_apb_timer_tick(t->id); + + t->int_status =3D 1; + dw_apb_timer_update_irq(t); + + if (t->control & DW_APB_TIMER_CONTROL_MODE_PERIODIC) { + reload =3D t->load ? t->load : 1; + } else { + reload =3D UINT32_MAX; + } + + ptimer_set_limit(t->ptimer, reload, 1); + ptimer_run(t->ptimer, 1); +} + +static uint64_t dw_apb_timer_read(void *opaque, hwaddr addr, + unsigned int size) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(opaque); + uint32_t value =3D 0; + + if (addr < DW_APB_TIMER_INT_STATUS) { + unsigned int idx =3D addr / DW_APB_TIMER_STRIDE; + hwaddr reg =3D addr % DW_APB_TIMER_STRIDE; + + if (idx < s->num_timers) { + DWAPBTimerChannel *t =3D &s->timers[idx]; + + switch (reg) { + case DW_APB_TIMER_N_LOAD_COUNT: + value =3D t->load; + break; + case DW_APB_TIMER_N_CURRENT_VALUE: + if (t->control & DW_APB_TIMER_CONTROL_ENABLE) { + value =3D ptimer_get_count(t->ptimer); + } + break; + case DW_APB_TIMER_N_CONTROL: + value =3D t->control; + break; + case DW_APB_TIMER_N_EOI: + t->int_status =3D 0; + dw_apb_timer_update_irq(t); + trace_dw_apb_timer_irq_clear(t->id); + break; + case DW_APB_TIMER_N_INT_STATUS: + value =3D t->int_status && + !(t->control & DW_APB_TIMER_CONTROL_INT); + break; + default: + break; + } + } + } else { + switch (addr) { + case DW_APB_TIMER_INT_STATUS: + for (int i =3D 0; i < s->num_timers; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + + value |=3D (t->int_status && + !(t->control & DW_APB_TIMER_CONTROL_INT)) << i; + } + break; + case DW_APB_TIMER_EOI: + for (int i =3D 0; i < s->num_timers; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + + t->int_status =3D 0; + dw_apb_timer_update_irq(t); + } + break; + case DW_APB_TIMER_RAW_INT_STATUS: + for (int i =3D 0; i < s->num_timers; i++) { + value |=3D s->timers[i].int_status << i; + } + break; + case DW_APB_TIMER_COMP_VERSION: + value =3D DW_APB_TIMER_COMP_VERSION_VAL; + break; + default: + break; + } + } + + trace_dw_apb_timer_read(addr, value); + return value; +} + +static void dw_apb_timer_write(void *opaque, hwaddr addr, + uint64_t value, unsigned int size) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(opaque); + + if (addr < DW_APB_TIMER_INT_STATUS) { + unsigned int idx =3D addr / DW_APB_TIMER_STRIDE; + hwaddr reg =3D addr % DW_APB_TIMER_STRIDE; + + if (idx < s->num_timers) { + DWAPBTimerChannel *t =3D &s->timers[idx]; + + switch (reg) { + case DW_APB_TIMER_N_LOAD_COUNT: + t->load =3D value; + break; + case DW_APB_TIMER_N_CONTROL: { + uint32_t old_control =3D t->control; + uint32_t new_control =3D value & DW_APB_TIMER_CONTROL_RW_M= ASK; + + t->control =3D new_control; + if ((new_control ^ old_control) & + DW_APB_TIMER_CONTROL_ENABLE) { + if (new_control & DW_APB_TIMER_CONTROL_ENABLE) { + dw_apb_timer_enable(t); + } else { + dw_apb_timer_disable(t); + } + } + if ((new_control ^ old_control) & + DW_APB_TIMER_CONTROL_INT) { + dw_apb_timer_update_irq(t); + } + break; + } + default: + break; + } + } + } + + trace_dw_apb_timer_write(addr, value); +} + +static const MemoryRegionOps dw_apb_timer_ops =3D { + .read =3D dw_apb_timer_read, + .write =3D dw_apb_timer_write, + .endianness =3D DEVICE_LITTLE_ENDIAN, + .impl =3D { + .min_access_size =3D 4, + .max_access_size =3D 4, + }, +}; + +static void dw_apb_timer_reset_hold(Object *obj, ResetType type) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(obj); + + for (int i =3D 0; i < s->num_timers; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + + ptimer_transaction_begin(t->ptimer); + ptimer_stop(t->ptimer); + ptimer_transaction_commit(t->ptimer); + + t->load =3D 0; + t->control =3D 0; + t->int_status =3D 0; + dw_apb_timer_update_irq(t); + } +} + +static const VMStateDescription vmstate_dw_apb_timer_channel =3D { + .name =3D "dw-apb-timer-channel", + .version_id =3D 1, + .minimum_version_id =3D 1, + .fields =3D (const VMStateField[]) { + VMSTATE_PTIMER(ptimer, DWAPBTimerChannel), + VMSTATE_CLOCK(clk, DWAPBTimerChannel), + VMSTATE_UINT32(load, DWAPBTimerChannel), + VMSTATE_UINT32(control, DWAPBTimerChannel), + VMSTATE_UINT32(int_status, DWAPBTimerChannel), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_dw_apb_timer =3D { + .name =3D "dw-apb-timer", + .fields =3D (const VMStateField[]) { + VMSTATE_STRUCT_VARRAY_UINT32(timers, DWAPBTimerState, + num_timers, 0, + vmstate_dw_apb_timer_channel, + DWAPBTimerChannel), + VMSTATE_END_OF_LIST() + } +}; + +static const Property dw_apb_timer_properties[] =3D { + DEFINE_PROP_UINT32("num-timers", DWAPBTimerState, num_timers, 1), +}; + +static void dw_apb_timer_init(Object *obj) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(obj); + + for (int i =3D 0; i < DW_APB_TIMER_MAX_TIMERS; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + g_autofree char *name =3D g_strdup_printf("timer[%d]", i); + + t->id =3D i; + t->clk =3D qdev_init_clock_in(DEVICE(obj), name, + dw_apb_timer_clk_update, t, + ClockUpdate); + } +} + +static void dw_apb_timer_realize(DeviceState *dev, Error **errp) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(dev); + SysBusDevice *sbd =3D SYS_BUS_DEVICE(dev); + + if (s->num_timers =3D=3D 0 || s->num_timers > DW_APB_TIMER_MAX_TIMERS)= { + error_setg(errp, "dw-apb-timer: num-timers must be between 1 and %= u", + DW_APB_TIMER_MAX_TIMERS); + return; + } + + for (int i =3D 0; i < s->num_timers; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + + if (!clock_has_source(t->clk)) { + error_setg(errp, "dw-apb-timer: timer[%u] clock must be connec= ted", + i); + return; + } + } + + for (int i =3D 0; i < s->num_timers; i++) { + DWAPBTimerChannel *t =3D &s->timers[i]; + + t->ptimer =3D ptimer_init(dw_apb_timer_tick, t, + PTIMER_POLICY_NO_IMMEDIATE_TRIGGER | + PTIMER_POLICY_NO_IMMEDIATE_RELOAD | + PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); + ptimer_transaction_begin(t->ptimer); + ptimer_set_limit(t->ptimer, UINT32_MAX, 1); + ptimer_transaction_commit(t->ptimer); + sysbus_init_irq(sbd, &t->irq); + + /* The source may have been connected before the ptimer existed. */ + dw_apb_timer_clk_update(t, ClockUpdate); + } + + memory_region_init_io(&s->mmio, OBJECT(dev), &dw_apb_timer_ops, + s, TYPE_DW_APB_TIMER, DW_APB_TIMER_MMIO_SIZE); + sysbus_init_mmio(sbd, &s->mmio); +} + +static void dw_apb_timer_unrealize(DeviceState *dev) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(dev); + + for (int i =3D 0; i < s->num_timers; i++) { + ptimer_free(s->timers[i].ptimer); + } +} + +static void dw_apb_timer_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + ResettableClass *rc =3D RESETTABLE_CLASS(klass); + + dc->realize =3D dw_apb_timer_realize; + dc->unrealize =3D dw_apb_timer_unrealize; + dc->vmsd =3D &vmstate_dw_apb_timer; + dc->desc =3D "Synopsys DesignWare APB timer"; + rc->phases.hold =3D dw_apb_timer_reset_hold; + device_class_set_props(dc, dw_apb_timer_properties); +} + +static const TypeInfo dw_apb_timer_info =3D { + .name =3D TYPE_DW_APB_TIMER, + .parent =3D TYPE_SYS_BUS_DEVICE, + .instance_size =3D sizeof(DWAPBTimerState), + .instance_init =3D dw_apb_timer_init, + .class_init =3D dw_apb_timer_class_init, +}; + +static void dw_apb_timer_register_type(void) +{ + type_register_static(&dw_apb_timer_info); +} + +type_init(dw_apb_timer_register_type) diff --git a/hw/timer/meson.build b/hw/timer/meson.build index 201b5d8316..fccc36540c 100644 --- a/hw/timer/meson.build +++ b/hw/timer/meson.build @@ -34,3 +34,4 @@ 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')) +system_ss.add(when: 'CONFIG_DW_APB_TIMER', if_true: files('dw-apb-timer.c'= )) diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 634ba1da27..7f592a96c8 100644 --- a/hw/timer/trace-events +++ b/hw/timer/trace-events @@ -1,5 +1,13 @@ # See docs/devel/tracing.rst for syntax documentation. =20 +# dw-apb-timer.c +dw_apb_timer_read(uint64_t addr, uint32_t val) "DW APB timer read: [0x%" P= RIx64 "] -> 0x%" PRIx32 +dw_apb_timer_write(uint64_t addr, uint64_t val) "DW APB timer write: [0x%"= PRIx64 "] <- 0x%" PRIx64 +dw_apb_timer_tick(int idx) "DW APB timer %d tick" +dw_apb_timer_irq_clear(int idx) "DW APB timer %d IRQ cleared" +dw_apb_timer_enable(int idx, uint32_t load) "DW APB timer %d enabled load= =3D0x%" PRIx32 +dw_apb_timer_disable(int idx) "DW APB timer %d disabled" + # slavio_timer.c slavio_timer_get_out(uint64_t limit, uint32_t counthigh, uint32_t count) "= limit 0x%"PRIx64" count 0x%x0x%08x" slavio_timer_irq(uint32_t counthigh, uint32_t count) "callback: count 0x%x= 0x%08x" diff --git a/include/hw/timer/dw-apb-timer.h b/include/hw/timer/dw-apb-time= r.h new file mode 100644 index 0000000000..f6b83ae5ca --- /dev/null +++ b/include/hw/timer/dw-apb-timer.h @@ -0,0 +1,40 @@ +/* + * Synopsys DesignWare APB timer + * + * Copyright (c) 2026 raoyi + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef DW_APB_TIMER_H +#define DW_APB_TIMER_H + +#include "hw/core/sysbus.h" +#include "hw/core/irq.h" +#include "hw/core/clock.h" +#include "qom/object.h" + +#define TYPE_DW_APB_TIMER "dw-apb-timer" +OBJECT_DECLARE_SIMPLE_TYPE(DWAPBTimerState, DW_APB_TIMER) + +#define DW_APB_TIMER_MAX_TIMERS 8 + +typedef struct DWAPBTimerChannel { + struct ptimer_state *ptimer; + Clock *clk; + qemu_irq irq; + unsigned int id; + uint32_t load; + uint32_t control; + uint32_t int_status; +} DWAPBTimerChannel; + +struct DWAPBTimerState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + uint32_t num_timers; + DWAPBTimerChannel timers[DW_APB_TIMER_MAX_TIMERS]; +}; + +#endif --=20 2.53.0 From nobody Fri Aug 28 00:12:36 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1786628316; cv=none; d=zohomail.com; s=zohoarc; b=QdPu6xwhjrah19fMdV6fU+WJphcjjTRx5z1kSu2Aeow54fOaxIVChZ5GGGMlIz8US7DhqCfMev6XindIeZOjz3UTrPTyMy4j23L0mRfIaVU3vLi2yR09f2AmJuNrP1R/E6q2AfnKzN8MureB4QuziG4o7qP8A2fVwlrIyqIGSQo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786628316; h=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=XxBiNV5RqMjj3YEM9w8aOuB458i6Nb2q9JRYJsSC1Ns=; b=GJLcXHpwjG5JS8oCV8mUqjpCZcQm6kgp4WXiOBVkB31MmmuO9NJEtSYFvk3/tcweG/JZ2HTQY9qxxLhMdm7rVrDJqpegKhdMeYo0SYV0NyNtYan+JU9TphF9yRStJDSMlYS/VYoyqZT/RpOhb/FR6Crd3X9q9nJMZwOcAdiJ32Y= 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=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1786628316515620.97762162526; Thu, 13 Aug 2026 06:38:36 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wuVcd-0005qV-Q5; Thu, 13 Aug 2026 09:37:27 -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 1wuVcc-0005pa-4H for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:26 -0400 Received: from mail-pl1-x631.google.com ([2607:f8b0:4864:20::631]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wuVca-0005VP-EU for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:25 -0400 Received: by mail-pl1-x631.google.com with SMTP id d9443c01a7336-2cf52d15d88so20869265ad.2 for ; Thu, 13 Aug 2026 06:37:24 -0700 (PDT) Received: from DESKTOP-DFGP8OG ([2409:8a55:ad2:6951::258]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-cbef6849625sm1078901a12.1.2026.08.13.06.37.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 06:37:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786628243; x=1787233043; darn=nongnu.org; h=content-transfer-encoding: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=XxBiNV5RqMjj3YEM9w8aOuB458i6Nb2q9JRYJsSC1Ns=; b=YDFcNOtd/zrfmYTm4TP4fGDK7W5MuHPT8CKDPZA7Q4AWjq/1uJVxl5tE3dYiUZu1nq RdD2yJSsGBJpwzuALrayIETTALX0jKRjo0YSceQY85wzdarS7jllf9pnoIH7z5jrkLhs JLHaC2OT7/bA91huOetAE8GzrMHxbKu/LPQwp0mSfkq/SBs7sVpk1SDHq925HzsDcp1x FAEDy1zmuV2U7CKG9/tCb1zim4pUFzNX9TX6C4bwx+GfJ+zPDIV6GkoYsVUs/1xxbNIG vaM78MzDs7MCbN2A7Uzb+ZZTkg84P86MJzfliRtCLnKoqbpkd3iSLpLMxHtRnOoX4Zz8 cKzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786628243; x=1787233043; h=content-transfer-encoding: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=XxBiNV5RqMjj3YEM9w8aOuB458i6Nb2q9JRYJsSC1Ns=; b=nDxd19atKIzjO/xgkNdIFuFwTJ5yzPY6YmvZE1fzH/9SWIgjSnX0/rDejPHaf1JC6Q urwVRFVuWW35SWoG117l1u5WzyC+LsigdSFyL6D3oQzfCH7Cb5xnXaeGdqeYcAKs+WlD 0VvzItiJ4hdYQ1i64b4O+Plnti2w3lFCIZC6JpR/+IBwM947XB7WochDjagivbovX7on oJUI8NnJNguBaQ1GsXgKLtWhU34YIfbn7lxhpeO14ijgn/+pQIX4bFQoDiVna7SwiYxq gjF3C5RjoUhGgm5XKL1EPoUOlhNQErGcZz67xfHC31U2plL7JPPjJsUAoQ5sb5CclrQt 1vRw== X-Gm-Message-State: AOJu0YxWUqIjPIC6ESJD5NWeHuy9BP+EzONfsmnM7BWB0hwL0bV+yvKm E2Pmz6j6WTqo210gPSiL/uWdHYucv5sUZ/RcJBDQlc2HGFX4xj6smFscXYiYJ0/rM5o= X-Gm-Gg: AR+sD10CNO3cLvQAL0b/AtbCkbpI5b+//Q227fj8BOcbq/7WR6v78L+OpI9NOV3txaU 8ldOZLv3Rtt6986wcyAl403G++iP9BjyyNgZvIeDvwfobFnB45GcfBCOtC39wL8/ewHqK0NsrWR StsdkmkFroNcVFZoE7X9YQRWOYM7P9b7SYaUtP7UdpGBUmFLtkJnzWOFh8Ly6iol6dURqfsk0k6 j4f2g7KaPR0dcSmp6lB3XvW29uMr3Ro36ly5o50TiQttpF4LRoiZyqQhxS1S7+LPJmEFcYJXnks bPmaNXqNztxpkNv0NTzzscQLk7lTIm6h+eEqx0+mfsuoXOdMynmQ/A3XTIDFz28MhHZ0ENT2oLV Um/Wh2ZekCucKutYCUW8aOCm8vUq57Gi7P6gwu6iHorn0BF6XBHEl2qsMOsqVMbxKH9jPdXA3wa uy6FTQ3a5m3eCwn3kW4wJcCVQLQptGTxaab//oWnWWaNu4oN42ahdqQZVSwLM= X-Received: by 2002:a05:6a21:151b:b0:3c3:6928:8b25 with SMTP id adf61e73a8af0-3cc552dea11mr8156251637.17.1786628242775; Thu, 13 Aug 2026 06:37:22 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, alistair.francis@wdc.com, palmer@dabbelt.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, bmeng.cn@gmail.com, philmd@oss.qualcomm.com, pbonzini@redhat.com, lvivier@redhat.com, farosas@suse.de, caojunze424@gmail.com, raoyi Subject: [PATCH v4 2/3] hw/riscv: add DesignWare APB timer to K230 board Date: Thu, 13 Aug 2026 21:36:42 +0800 Message-ID: <20260813133643.20380-3-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813133643.20380-1-rao232328@gmail.com> References: <20260813133643.20380-1-rao232328@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::631; envelope-from=rao232328@gmail.com; helo=mail-pl1-x631.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=unavailable 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 @gmail.com) X-ZM-MESSAGEID: 1786628318667158500 Content-Type: text/plain; charset="utf-8" Wire up the DesignWare APB timer to the K230 SoC with num-timers=3D6 and a 6.25 MHz clock. Connect timer IRQs to the PLIC. Remove the previous unimplemented timer stub. Signed-off-by: raoyi --- hw/riscv/Kconfig | 1 + hw/riscv/k230.c | 33 ++++++++++++++++++++++++++++++--- include/hw/riscv/k230.h | 8 ++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index de37c08cae..c2c01af6ee 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -162,3 +162,4 @@ config K230 select SERIAL_MM select UNIMP select K230_WDT + select DW_APB_TIMER diff --git a/hw/riscv/k230.c b/hw/riscv/k230.c index 656f28190c..78a05492ad 100644 --- a/hw/riscv/k230.c +++ b/hw/riscv/k230.c @@ -24,6 +24,8 @@ #include "target/riscv/cpu.h" #include "hw/core/loader.h" #include "hw/core/sysbus.h" +#include "hw/core/clock.h" +#include "hw/core/qdev-clock.h" #include "hw/riscv/k230.h" #include "hw/riscv/boot.h" #include "hw/riscv/machines-qom.h" @@ -37,6 +39,9 @@ #define K230_DIRECT_KERNEL_ADDR 0x8200000 #define K230_DIRECT_DTB_ADDR 0xa000000 =20 +#define K230_TIMER_NUM_CHANNELS 6 +#define K230_TIMER_DEFAULT_FREQ 6250000 + static const MemMapEntry memmap[] =3D { [K230_DEV_DDRC] =3D { 0x00000000, 0x80000000 }, [K230_DEV_KPU_L2_CACHE] =3D { 0x80000000, 0x00200000 }, @@ -110,6 +115,19 @@ static void k230_soc_init(Object *obj) object_initialize_child(obj, "c908-cpu", cpu0, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "k230-wdt0", &s->wdt[0], TYPE_K230_WDT); object_initialize_child(obj, "k230-wdt1", &s->wdt[1], TYPE_K230_WDT); + object_initialize_child(obj, "dw-apb-timer", &s->timer, + TYPE_DW_APB_TIMER); + + qdev_prop_set_uint32(DEVICE(&s->timer), "num-timers", + K230_TIMER_NUM_CHANNELS); + + Clock *timer_clk =3D clock_new(OBJECT(s), "timer-clk"); + clock_set_hz(timer_clk, K230_TIMER_DEFAULT_FREQ); + for (int i =3D 0; i < K230_TIMER_NUM_CHANNELS; i++) { + g_autofree char *clock_name =3D g_strdup_printf("timer[%d]", i); + + qdev_connect_clock_in(DEVICE(&s->timer), clock_name, timer_clk); + } =20 qdev_prop_set_uint32(DEVICE(cpu0), "hartid-base", 0); qdev_prop_set_string(DEVICE(cpu0), "cpu-type", TYPE_RISCV_CPU_THEAD_C9= 08); @@ -191,6 +209,18 @@ static void k230_soc_realize(DeviceState *dev, Error *= *errp) k230_create_uart(sys_mem, DEVICE(s->c908_plic), i); } =20 + /* Timer */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->timer), errp)) { + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->timer), 0, memmap[K230_DEV_TIMER].b= ase); + + for (int i =3D 0; i < K230_TIMER_NUM_CHANNELS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timer), i, + qdev_get_gpio_in(DEVICE(s->c908_plic), + K230_TIMER0_IRQ + i)); + } + /* Watchdog */ for (int i =3D 0; i < 2; i++) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->wdt[i]), errp)) { @@ -283,9 +313,6 @@ static void k230_soc_realize(DeviceState *dev, Error **= errp) create_unimplemented_device("iomux", memmap[K230_DEV_IOMUX].base, memmap[K230_DEV_IOMUX].size); =20 - create_unimplemented_device("timer", memmap[K230_DEV_TIMER].base, - memmap[K230_DEV_TIMER].size); - create_unimplemented_device("wdt0", memmap[K230_DEV_WDT0].base, memmap[K230_DEV_WDT0].size); =20 diff --git a/include/hw/riscv/k230.h b/include/hw/riscv/k230.h index 592e1c26bf..42a36664eb 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -18,6 +18,7 @@ #include "hw/core/boards.h" #include "hw/riscv/riscv_hart.h" #include "hw/watchdog/k230_wdt.h" +#include "hw/timer/dw-apb-timer.h" =20 #define C908_CPU_HARTID (0) =20 @@ -33,6 +34,7 @@ typedef struct K230SoCState { RISCVHartArrayState c908_cpu; /* Small core */ =20 K230WdtState wdt[2]; + DWAPBTimerState timer; MemoryRegion sram; MemoryRegion bootrom; =20 @@ -127,6 +129,12 @@ enum { K230_UART2_IRQ =3D 18, K230_UART3_IRQ =3D 19, K230_UART4_IRQ =3D 20, + K230_TIMER0_IRQ =3D 101, + K230_TIMER1_IRQ =3D 102, + K230_TIMER2_IRQ =3D 103, + K230_TIMER3_IRQ =3D 104, + K230_TIMER4_IRQ =3D 105, + K230_TIMER5_IRQ =3D 106, K230_WDT0_IRQ =3D 107, K230_WDT1_IRQ =3D 108, }; --=20 2.53.0 From nobody Fri Aug 28 00:12:36 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=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1786628313; cv=none; d=zohomail.com; s=zohoarc; b=E97HnyXI603XcRmbPRh5dNIyApQ3soKJy1cY4lSn8i+vCY3L3J2mInInmPfUQ/7yHvh6yaHarDSwmxvBzxGVSQukemOyCogFXSVNP+2fJ1NAZMHKY4tZouwsnLfg+hnoeVZOgPig8PuI4kgPorG18cCYozCWuZEuIdpMNScrUCs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786628313; h=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=pkgNS/wFPS/nmbz6lf4/O2cmnILygdjZpZuFH7CC0uQ=; b=FNK5sC4vIWJR5GJ1Qt5jmD5q2BSjL4DN4Xbc85afFnIgi9+rUrneZVM7tOxrOcDKwHvpikhg5wM1E0rA7b5IbGpgG72HBNd7ECKJ0P9grvu70cC+a9nsoWCsYJ6/Suo+h40zW3matIL12l+grH5qZOvpp/ZZsGd/deAFp1z76w8= 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=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 178662831338610.62813710779119; Thu, 13 Aug 2026 06:38:33 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wuVcj-0005rU-7A; Thu, 13 Aug 2026 09:37:33 -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 1wuVch-0005qk-Ku for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:31 -0400 Received: from mail-pf1-x433.google.com ([2607:f8b0:4864:20::433]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wuVcf-0005W8-EM for qemu-devel@nongnu.org; Thu, 13 Aug 2026 09:37:31 -0400 Received: by mail-pf1-x433.google.com with SMTP id d2e1a72fcca58-84faf87d19dso832109b3a.3 for ; Thu, 13 Aug 2026 06:37:29 -0700 (PDT) Received: from DESKTOP-DFGP8OG ([2409:8a55:ad2:6951::258]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-cbef6849625sm1078901a12.1.2026.08.13.06.37.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Aug 2026 06:37:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786628248; x=1787233048; darn=nongnu.org; h=content-transfer-encoding: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=pkgNS/wFPS/nmbz6lf4/O2cmnILygdjZpZuFH7CC0uQ=; b=sAzZ7Th+hGN997cHFJGMuyvVwIVlP4zzVX/mZ8gET/PtdlvLc86hbkDJW0/Zi+PL2/ g7NZLvKA51nqFDIDbBPhlRZxBJYu2/2wbc40kqb6HPCY1XGeAloty+XHG7dWe00WcKbI WQ55Swwj2g4Mq9071GNehsjO07WgG0vqHOwmCGfz7J1Evs8fLq3Qut31salpd75IBu+Z HGNqD8YETlx7LbwEF+LB5GMyS/JybPoRZGOcec4sDmjPFVtRpIPUOLoBze8FTruhKuVS TEXeUIEyqvo9611nEcbz2fRL+nwaVvD8bboLZ/DxEchETDFlbEjTct14QRnouXhSWXs6 HDXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786628248; x=1787233048; h=content-transfer-encoding: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=pkgNS/wFPS/nmbz6lf4/O2cmnILygdjZpZuFH7CC0uQ=; b=UymsHEBno3pTmPNFgUGOrF9x0ptgMhC4SUyThdeKCfg/2Z6kZnfMfS6sRlcliACGat QInBSsjNwRRGOxcvsw69/xGTGZHgbQ/k+ZGgriKe1UgMmUb1Ir4UKUUoEdDVWuxus7J6 Sm5HCh6obgNoLi9qFW2AkkqQfEkh18kJA1ehFLyhy+pe7aE6oJPLXXDl4/ES8BIBsaxY amHlRLAnOGfMtZwuvbDrcdpUjnUfQSC/pBJroFeLQ1W20I0Z9xDisrV1W2Hi5QFLt4PD nEa84Jb0/PwiQGe163AyIKkZ2vRhiRUiMby7mV55sYauLZSOfRwpl1eXjlHvdDAgkRMz JzPw== X-Gm-Message-State: AOJu0Yy/51lNHtgsTLZxA+AG8sjHrvNFKEsTXvNpTRKLdAiiZ/dNX04c p0q4fw+6VLvh3lVdtX3kQ9fM51OxqBCpG8riyB8A0KKvyMIxjY4fErVONnwHBwOhlCo= X-Gm-Gg: AR+sD11c6WJACO9ySR6ps7f+6SFJKYo6hzJPMZTPhSu6Pf2tTKvLURnmwr+OEq518OK cnCvuIXCkHD7EyMm9uEu7zbPTUVa5ngJy43SUBNWmLAW7T3flJnkOZc/AaA57AC27hNrJPLEV73 EFbkrQrR4j2e3LywB9tGj5XlgH2+efrrmM/akOovzbPmSDyNtRvGHmaC53YBTc2bxgMV5XWRJN9 s+ramag1eeN2Nqy2Exjq3I7Vm0LKy5xwr1aijNG4ab9a1unzQFR4Guw0MnbfleTpwww0rVfXaSI GVJluZL1QemvIuhGRMCo2d+iQZ0tj5NeoGbY1xSgXN5Q+fpyRcUTJDZvez6NDOH9xQ+kKIpGIdw omPwCRY+jQt3Z8twwZhDIb1sCWsN5dGbDJgp8QtxJ+L1g2dyq/9/n+p8oqAs0rmcteqHL91JMx4 EqWiM48xRXOlvvykAOGWl+FC18XDWOggPJtXkX70oGJh55gzHq X-Received: by 2002:a05:6a00:4c9b:b0:848:2f2c:b2c8 with SMTP id d2e1a72fcca58-84fc6e5b2f9mr6540515b3a.24.1786628247907; Thu, 13 Aug 2026 06:37:27 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, alistair.francis@wdc.com, palmer@dabbelt.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, bmeng.cn@gmail.com, philmd@oss.qualcomm.com, pbonzini@redhat.com, lvivier@redhat.com, farosas@suse.de, caojunze424@gmail.com, raoyi Subject: [PATCH v4 3/3] tests/qtest: add k230 dwapb timer test Date: Thu, 13 Aug 2026 21:36:43 +0800 Message-ID: <20260813133643.20380-4-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260813133643.20380-1-rao232328@gmail.com> References: <20260813133643.20380-1-rao232328@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable 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=2607:f8b0:4864:20::433; envelope-from=rao232328@gmail.com; helo=mail-pf1-x433.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.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, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, 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 @gmail.com) X-ZM-MESSAGEID: 1786628315184158500 Content-Type: text/plain; charset="utf-8" Add qtest coverage for K230 DW APB timer including free-running, periodic, interrupt mask, disable behavior, current value, dynamic reload, and multi-channel scenarios. Add timer test file to MAINTAINERS. Signed-off-by: raoyi Reviewed-by: Bin Meng --- MAINTAINERS | 1 + tests/qtest/k230-dwapb-timer-test.c | 274 ++++++++++++++++++++++++++++ tests/qtest/meson.build | 4 +- 3 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/k230-dwapb-timer-test.c diff --git a/MAINTAINERS b/MAINTAINERS index cf689433ff..82e5643a93 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1830,6 +1830,7 @@ F: hw/timer/dw-apb-timer.c F: include/hw/riscv/k230.h F: include/hw/watchdog/k230_wdt.h F: include/hw/timer/dw-apb-timer.h +F: tests/qtest/k230-dwapb-timer-test.c F: tests/qtest/k230-wdt-test.c =20 RX Machines diff --git a/tests/qtest/k230-dwapb-timer-test.c b/tests/qtest/k230-dwapb-t= imer-test.c new file mode 100644 index 0000000000..a74f36999e --- /dev/null +++ b/tests/qtest/k230-dwapb-timer-test.c @@ -0,0 +1,274 @@ +/* + * QTest testcase for the DesignWare APB timer through the K230 machine + * + * Copyright (c) 2026 raoyi + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "qemu/timer.h" +#include "libqtest.h" + +#define TIMER_BASE 0x91105800 +#define K230_TIMER_NUM_CHANNELS 6 +#define K230_TIMER_DEFAULT_FREQ 6250000 + +#define DW_APB_TIMER_STRIDE 0x14 +#define DW_APB_TIMER_N_LOAD_COUNT 0x00 +#define DW_APB_TIMER_N_CURRENT_VALUE 0x04 +#define DW_APB_TIMER_N_CONTROL 0x08 +#define DW_APB_TIMER_N_EOI 0x0c +#define DW_APB_TIMER_N_INT_STATUS 0x10 +#define DW_APB_TIMER_INT_STATUS 0xa0 +#define DW_APB_TIMER_EOI 0xa4 +#define DW_APB_TIMER_RAW_INT_STATUS 0xa8 +#define DW_APB_TIMER_CONTROL_ENABLE BIT(0) +#define DW_APB_TIMER_CONTROL_MODE_PERIODIC BIT(1) +#define DW_APB_TIMER_CONTROL_INT BIT(2) + +#define TIMER_REG(n, reg) (TIMER_BASE + (n) * DW_APB_TIMER_STRIDE + (reg)) +#define TIMER_TICK_NS (NANOSECONDS_PER_SECOND / K230_TIMER_DEFAULT_FREQ) + +static void timer_load(QTestState *qts, int n, uint32_t value) +{ + qtest_writel(qts, TIMER_REG(n, DW_APB_TIMER_N_LOAD_COUNT), value); +} + +static void timer_enable(QTestState *qts, int n, uint32_t ctrl) +{ + qtest_writel(qts, TIMER_REG(n, DW_APB_TIMER_N_CONTROL), ctrl); +} + +static void timer_disable(QTestState *qts, int n) +{ + qtest_writel(qts, TIMER_REG(n, DW_APB_TIMER_N_CONTROL), 0); +} + +static uint32_t timer_get_and_clear_status(QTestState *qts, int n) +{ + uint32_t int_status =3D qtest_readl(qts, + TIMER_REG(n, DW_APB_TIMER_N_INT_STATUS)); + + if (int_status) { + qtest_readl(qts, TIMER_REG(n, DW_APB_TIMER_N_EOI)); + } + + return int_status; +} + +static void test_timer_free_running(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + timer_load(qts, 0, 100); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE); + + qtest_clock_step(qts, 101ULL * TIMER_TICK_NS + 1); + g_assert_cmphex(timer_get_and_clear_status(qts, 0), =3D=3D, 1); + + qtest_clock_step(qts, 10ULL * TIMER_TICK_NS); + uint32_t cur =3D qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)); + g_assert_cmphex(cur, <, UINT32_MAX); + g_assert_cmphex(cur, >, 0); + + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_INT_STATUS)), =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_timer_periodic(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + int i; + + timer_load(qts, 0, 100); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + + for (i =3D 0; i < 3; i++) { + qtest_clock_step(qts, 101ULL * TIMER_TICK_NS + 1); + g_assert_cmphex(timer_get_and_clear_status(qts, 0), =3D=3D, 1); + uint32_t cur =3D qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)); + g_assert_cmphex(cur, <=3D, 100); + } + + qtest_quit(qts); +} + +static void test_timer_int_mask(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + timer_load(qts, 0, 100); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC | + DW_APB_TIMER_CONTROL_INT); + + qtest_clock_step(qts, 101ULL * TIMER_TICK_NS + 1); + + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_INT_STATUS)) & 1, =3D=3D= , 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_BASE + DW_APB_TIMER_INT_STATUS), =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_BASE + DW_APB_TIMER_RAW_INT_STATUS) & 1, =3D= =3D, 1); + + /* Unmasking a pending interrupt must assert it immediately. */ + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_INT_STATUS)), =3D=3D, 1); + g_assert_cmphex(qtest_readl(qts, + TIMER_BASE + DW_APB_TIMER_INT_STATUS) & 1, =3D=3D, 1= ); + + qtest_quit(qts); +} + +static void test_timer_disable_clears_irq(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + timer_load(qts, 0, 100); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + + qtest_clock_step(qts, 101ULL * TIMER_TICK_NS + 1); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_INT_STATUS)) & 1, =3D=3D= , 1); + + timer_disable(qts, 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_INT_STATUS)) & 1, =3D=3D= , 0); + + qtest_quit(qts); +} + +static void test_timer_current_disabled(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + /* TRM: "A '0' is always read back when the timer is not enabled" */ + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)), =3D=3D,= 0); + + timer_load(qts, 0, 9999); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)), =3D=3D,= 0); + + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE); + qtest_clock_step(qts, 10ULL * TIMER_TICK_NS); + uint32_t cur_enabled =3D qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)); + g_assert_cmphex(cur_enabled, >, 0); + g_assert_cmphex(cur_enabled, <, UINT32_MAX); + + timer_disable(qts, 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)), =3D=3D,= 0); + + qtest_quit(qts); +} + +static void test_timer_dynamic_reload(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + uint32_t cur; + + timer_load(qts, 0, 1000); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + + qtest_clock_step(qts, 100ULL * TIMER_TICK_NS); + + timer_load(qts, 0, 200); + + qtest_clock_step(qts, 901ULL * TIMER_TICK_NS + 1); + g_assert_cmphex(timer_get_and_clear_status(qts, 0), =3D=3D, 1); + + qtest_clock_step(qts, 100ULL * TIMER_TICK_NS); + cur =3D qtest_readl(qts, TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)); + g_assert_cmphex(cur, =3D=3D, 99); + + qtest_quit(qts); +} + +static void test_timer_all_channels(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + int i; + + for (i =3D 0; i < K230_TIMER_NUM_CHANNELS; i++) { + timer_load(qts, i, 100 + i * 50); + timer_enable(qts, i, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + } + + /* Step past timer 0 expiry (load=3D100) - only timer 0 should fire */ + qtest_clock_step(qts, 101ULL * TIMER_TICK_NS + 1); + uint32_t sts =3D qtest_readl(qts, TIMER_BASE + DW_APB_TIMER_INT_STATUS= ); + g_assert_cmphex(sts & 1, =3D=3D, 1); + g_assert_cmphex(sts & 0x3e, =3D=3D, 0); + + /* Step to timer 1 expiry (another 50 ticks) */ + qtest_clock_step(qts, 50ULL * TIMER_TICK_NS + 1); + sts =3D qtest_readl(qts, TIMER_BASE + DW_APB_TIMER_INT_STATUS); + g_assert_cmphex(sts & 0x3, =3D=3D, 0x3); + g_assert_cmphex(sts & 0x3c, =3D=3D, 0); + + /* Step to expiry of all remaining timers (another 200 ticks) */ + qtest_clock_step(qts, 200ULL * TIMER_TICK_NS + 1); + sts =3D qtest_readl(qts, TIMER_BASE + DW_APB_TIMER_INT_STATUS); + g_assert_cmphex(sts, =3D=3D, 0x3f); + + /* EOI_ALL clears all */ + qtest_readl(qts, TIMER_BASE + DW_APB_TIMER_EOI); + sts =3D qtest_readl(qts, TIMER_BASE + DW_APB_TIMER_INT_STATUS); + g_assert_cmphex(sts, =3D=3D, 0); + + qtest_quit(qts); +} + +static void test_timer_reset(void) +{ + QTestState *qts =3D qtest_init("-machine k230"); + + timer_load(qts, 0, 100); + timer_enable(qts, 0, DW_APB_TIMER_CONTROL_ENABLE | + DW_APB_TIMER_CONTROL_MODE_PERIODIC); + qtest_clock_step(qts, 10ULL * TIMER_TICK_NS); + + qtest_system_reset(qts); + + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_LOAD_COUNT)), =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CONTROL)), =3D=3D, 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_REG(0, DW_APB_TIMER_N_CURRENT_VALUE)), =3D=3D,= 0); + g_assert_cmphex(qtest_readl(qts, + TIMER_BASE + DW_APB_TIMER_RAW_INT_STATUS), =3D=3D, 0= ); + + qtest_quit(qts); +} + +int main(int argc, char *argv[]) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/dw-apb-timer/free_running", test_timer_free_running); + qtest_add_func("/dw-apb-timer/periodic", test_timer_periodic); + qtest_add_func("/dw-apb-timer/int_mask", test_timer_int_mask); + qtest_add_func("/dw-apb-timer/disable_clears_irq", + test_timer_disable_clears_irq); + qtest_add_func("/dw-apb-timer/current_disabled", + test_timer_current_disabled); + qtest_add_func("/dw-apb-timer/dynamic_reload", + test_timer_dynamic_reload); + qtest_add_func("/dw-apb-timer/all_channels", test_timer_all_channels); + qtest_add_func("/dw-apb-timer/reset", test_timer_reset); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 56ff860e21..295a724116 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -297,7 +297,9 @@ qtests_riscv64 =3D ['riscv-csr-test'] + \ (config_all_devices.has_key('CONFIG_IOMMU_TESTDEV') and config_all_devices.has_key('CONFIG_RISCV_IOMMU') ? ['iommu-riscv-test'] : []) + \ - (config_all_devices.has_key('CONFIG_K230') ? ['k230-wdt-test'] : []) + (config_all_devices.has_key('CONFIG_K230') and + config_all_devices.has_key('CONFIG_DW_APB_TIMER') ? + ['k230-wdt-test', 'k230-dwapb-timer-test'] : []) =20 qtests_hexagon =3D ['boot-serial-test'] =20 --=20 2.53.0