From nobody Mon Sep 28 00:10:24 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=1787145625; cv=none; d=zohomail.com; s=zohoarc; b=KpOWukiTCbrHOeblGErnySTfFKZ1vDbO/k0eubvkdMlLzQ/IEAsjk14Ka5T3iVFWu4dkxuwo2qCYHPHKPd3+95tBRriwmbRCPKVERFkexkL6nNcqBNQjMSOUQRqn5n7olpbUPqbYkTyetsEC387pumVm0NRUmyNHw6tntdEU07s= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1787145625; 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=DAZhmr7lFpnfTihWTbQ+euv+X6D6ZMXRKGB9vPdGUwk=; b=dL++zAt0bx39ledrBxwO4LahI7Mi9/v9YIFNa1VAT7+ZRsU9/x1nTgL8X/bRs3qxbvxsRKqUTvOAsuBKvUxrlLnZtxIrPczm99AQnKO5hJXz7RIbBAyqoSjidaLEUEr9yXwFOTsxBgsJIKRR+WCsLCOVDU9PLUHvrUGB3tmfNvQ= 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 1787145625159193.2635558399843; Wed, 19 Aug 2026 06:20:25 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wwgCN-0005B6-2n; Wed, 19 Aug 2026 09:19:19 -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 1wwgCL-0005Aj-Ce for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:17 -0400 Received: from mail-pj1-x102e.google.com ([2607:f8b0:4864:20::102e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wwgCI-0004qs-RO for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:17 -0400 Received: by mail-pj1-x102e.google.com with SMTP id 98e67ed59e1d1-38f620399a0so901344a91.2 for ; Wed, 19 Aug 2026 06:19:14 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([156.226.169.41]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3957fb12145sm2734387a91.4.2026.08.19.06.19.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Aug 2026 06:19:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787145553; x=1787750353; 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=DAZhmr7lFpnfTihWTbQ+euv+X6D6ZMXRKGB9vPdGUwk=; b=DpOixrubEQ3Gcywibjr2Px5mrATi4IvtAExRoFCjeUGV62CAC273QbrH3aM5SfGL6K NdzoXvIngNqS+Ux5Ddc3I6iSNVN+kI8DBiGWmaQIeoSVzA5+zYSnNlrpJ6f8qfLLOVmt D+/CtUvxP1MClYtWwTaXL8tNlehv3eNu9JdhwbxUD6ZouIyepmfRxeSQZiyect1y//rK V4G1hfjgoov5XAQIsMy88THMeX6nTwtSYN9SYQZn1KA8cLfo2JNw+E1Q/FPnYNDkMlzk jW4vXzqdQB7oO5LsXlssla9ObMYjDUy892WQX8/zdIdSy+CSwve4codaGK272LtEK1g7 9kGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787145553; x=1787750353; 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=DAZhmr7lFpnfTihWTbQ+euv+X6D6ZMXRKGB9vPdGUwk=; b=S5epc4fEwXnIr8XMO99CU4CfHNvBNE17qVfk+pY4O8+aeu6LAc8W6cETAVM5YKYgGG YV6P8GyhfJhL+JRM2ArJubMNCOrAdIxU7UCTsN/bQ77NVKZh5syaJL/gQ0sJcIcUt+eU EoRa6a7gt7xOgZDTVDflVJ/Bd2VZ5rDOmB0VEcD0r4O5boJMcHHDr6mC7AmRQ6MixLLf AZ84GJpi4Wnryt0zTZIRtrbg9zJQJ3815tubEtzgsCWs4qA6HlwgBLsM8U5zF2vQtrOY vib+/OWthQwMeX+SlBeopI7sC86GY1qhgf0ZPTkelMwWGCgjz1XWWl5fmeW4prHiYeyc 5jdw== X-Gm-Message-State: AFuF++mZC0fH8wfDO23aIc9zdeAjA/eJtpPJXWmCRPmf8/2WIQkJohZN R9d1W+g4KyZ6i4iRTcTR/j//noN1fzXOHVJKAsENLnbP9AFMVkErQLvkVsfoHA== X-Gm-Gg: AR+sD12Eghe65NWHxAsz6Cvgg63/3UH6BHU53U10itjwF9EEhhFqwNnEW2q7PoXvVcH lw4VVeeMl5r8gBkVE1AeY75FNv6sCu42IslfF4Rpeg4l6EpiUKEdZ6D3ODmadunMwehQWPLImQR udxjZ4e803UcNDW309lvumVLDaGl2Fd4ZKvmhZgC96Dk19PVTkwPFt64YZrSXcO0v5wtUdZo70/ /PZeTj3DdyRbgdnmKDCVLx9zzd6aihktyx2qRHvEZ1SR+CHhF/wGNyLsoEX78eh5wcFCBcQwvT5 msxsoVhzhrXZJe90IHNEWLpEhhY9Hxdo4n9kQUN5i/4Mnsu2rc3CrpVr9sQSjhXtlumjdeCjv+W JEa7FygI1yHi9bIvOEtLDZ1mO9yHlM+GHl62w1j3JNp/MFNY7wiV1MnAQ/yVpLhV072J8PBSiAE SSj/gJlFXnuWV9gtPC/qltXJTpG71gC7dPvzIZE0zYM8PIICoaAzIXhlb+BlGG/PqtjsZo2g== X-Received: by 2002:a17:90b:5102:b0:392:b509:b1a5 with SMTP id 98e67ed59e1d1-395810caaf3mr9152360a91.14.1787145553017; Wed, 19 Aug 2026 06:19:13 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Cc: Chao Liu , Alistair Francis , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , caojunze424 , Bin Meng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , raoyi Subject: [PATCH v5 1/3] hw/timer: add DesignWare APB timer model Date: Wed, 19 Aug 2026 21:18:57 +0800 Message-ID: <20260819131859.9583-2-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260819131859.9583-1-rao232328@gmail.com> References: <20260819131859.9583-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::102e; envelope-from=rao232328@gmail.com; helo=mail-pj1-x102e.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: 1787145626591158500 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 --- 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..86e1fac43f --- /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_MASK 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_MASK)); +} + +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_MASK); + 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_MASK)) <= < 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_MASK) { + 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 Mon Sep 28 00:10:24 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=1787145614; cv=none; d=zohomail.com; s=zohoarc; b=OzwyB8YQshygWtRhVCyDd56mU0MybT2kYBXtKXWYd48AoOQsIMjZJXGKxgh+OQqCH8yeQ1kSFMRP8AR6mK1yVqNl1z28TKuu8/GDTpZT5eJaJcmkwFQNftEvLLiMfN+mkcf8GDLs7mcAPGZSf8klikHkBubZzGElgihSsEe00SE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1787145614; 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=ePfGipNK4v19XZb3CA7EOq8w7Q1IMhBnTuf0QhDiJOM=; b=MVGX64sbC2hsgWoN36XgqYJfsd+gMS6+5W3AYfwSTxzh0conWgGmxAtlJ4q3oUIRMXeyvCMhPFn70FLyFPYoPRPnyyqUcf3QQz3ybA9pyhaOvxKvE2IwL0swRtQWSA3Dk01iaYBOts/7vU4QDV/OJyUys5m8ZfuCNyW9l4uhVNE= 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 1787145614991351.5592545585249; Wed, 19 Aug 2026 06:20:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wwgCP-0005Bs-Gd; Wed, 19 Aug 2026 09:19:21 -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 1wwgCO-0005Bb-88 for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:20 -0400 Received: from mail-pj1-x102a.google.com ([2607:f8b0:4864:20::102a]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wwgCM-0004rU-7d for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:19 -0400 Received: by mail-pj1-x102a.google.com with SMTP id 98e67ed59e1d1-382ef647e20so1082219a91.1 for ; Wed, 19 Aug 2026 06:19:17 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([156.226.169.41]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3957fb12145sm2734387a91.4.2026.08.19.06.19.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Aug 2026 06:19:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787145557; x=1787750357; 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=ePfGipNK4v19XZb3CA7EOq8w7Q1IMhBnTuf0QhDiJOM=; b=oOZn16O4PkWf9YfLCJQz0JGcq5+qLCxGko4SEKk3NdTp+96ezWMmuzjCMgYeSLwLxm 7n1Spoxb6b/UXxIk7UlZfhWPj9SrfOe8+9isobDg6PMdHstvfkKGHVs2BFI/+9JBvrGU FozNuFlYw1orKqV9exUw0HopQX1N1gUSlonGAstgNdoT9j17LOyJOjQ7g8pAeOnvsonY pc6U85LZZEA5ZftjLEZX/3HbGBBqHXg103wIw+lXy3VaeBpNhZCDt2OZJ84BN9m/iVir W5YGtf7vKQC77TSDM0sNbPdhrUEWbXm1QX25NXe3UU08WSWe1/yTomGhfg48DtgZQyye tHrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787145557; x=1787750357; 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=ePfGipNK4v19XZb3CA7EOq8w7Q1IMhBnTuf0QhDiJOM=; b=hFbHwq3o4vgs/r/pgmn4AtAuCdNnHFqrbrUuo2WheLoJMPLZxHbAJemoMlsRioLOWS yEZjbWGgpUaG+FlDifQH7Df9FJMiv61//jBfRsbwQV+IXf2adMNb6v/VYtG1dwPfrjs/ oyUKnjyY9WTsLeX2Mh4tPMbVOKtJJOF5IH5qwrsb9NM/ceq+EvQXoeCvWU+1W4Z8FL/8 FMhyEpa//HqgxijBEKMypszE11tzKpa5ozmthwZ8f3jcP8vOCOTpPKeUKV4yjL2LmKHO XnL4aNYPsVgpdHfmNX4ydlAuHg7q+pz6YZf1m9pPOeGRVB1raajTmRk53zghOl9uCViK eKog== X-Gm-Message-State: AFuF++lT3On41goAWd5VUha5frrRl3vMxOPqLiKtXaOt8TJNUJ7HqzSR SANtMBi2Atizt8dmHVx54g6uiSJT6FHuLxjBrf/cMwd/cBhGoCH0/GVrwU5BUv1GNp8ZCw== X-Gm-Gg: AR+sD11pd+wgbn0EoNLemUhwlz8rq7BVtl7OSN+MWn57hVKj+Waa8Fn0qh8ule8qRmj sDNM/ZIlKoUw97rXLEqfhgWv9EcSzSqtJplN0zKvdkpcv/7oH6QQCUCdL9AfO3jv49RtfwZxMWg vBYTWpwnHbgLtCI00+9t+CqAALSJ05C12AjSleNCX8PH4GHTJWpQLUt9Wh+yvnq/fJftl+74y9D DGrmp7aZI1bpa/0kI541A1bhbgWzNh6XsojqDua04+dCfCXO8Afxz91yxv0VL5RuN+UR10FOLNm I+slzZVpbfL2YTF54MJvMYrtmMBhkY5letKHgMCglM6j14OS0daqEBxj5Qctk2kvfF+mig6+rSE fnYZ5q4jHivhRCDyrBY2FNArv0Qn28p20BWZzcDNDtWVFaBOnIjo3q/hkHufocnTB8V3BsqpouK +/ZgegjgInPwJB/nnIfCLgvXPFAMKn76XcvfJ/IcdYefpYVcA0T2z/A20I4NaIXINCh2sUzG9Dm XVhLqmm X-Received: by 2002:a17:90b:4a8d:b0:38e:ad9d:1161 with SMTP id 98e67ed59e1d1-39580553dfamr8976336a91.0.1787145556612; Wed, 19 Aug 2026 06:19:16 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Cc: Chao Liu , Alistair Francis , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , caojunze424 , Bin Meng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , raoyi Subject: [PATCH v5 2/3] hw/riscv: add DesignWare APB timer to K230 board Date: Wed, 19 Aug 2026 21:18:58 +0800 Message-ID: <20260819131859.9583-3-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260819131859.9583-1-rao232328@gmail.com> References: <20260819131859.9583-1-rao232328@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" 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::102a; envelope-from=rao232328@gmail.com; helo=mail-pj1-x102a.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: 1787145616515158501 Wire up the DesignWare APB timer to the K230 SoC with num-timers=3D6 and a 50 MHz clock. Connect timer IRQs to the PLIC. Remove the previous unimplemented timer stub. Signed-off-by: raoyi Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- 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..2e641ffec4 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 50000000 + 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 Mon Sep 28 00:10:24 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=1787145615; cv=none; d=zohomail.com; s=zohoarc; b=Sq84wlxkL1wXhtNCnRotJ6LjkDPeYrjbLK/FdJyoQi41A3Bfcx+yMlVkOl6B+oC84tnM36CWNioxWB/9bcnRIUujiYaSLYZJuDbpNAWjksnAoty7V9s0cX0zzD7Dvv9uJr03HnFjTFmZUxwal+izrWI97MmUhD/M7wTKi3eMDZM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1787145615; 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=5fSJnWphlhlECSW+wv6njLNgjR+jeMC/7N9v4OiIjw0=; b=Hwl1G9aThe/YI8TTGBYsilZzhFX04ATEjd3xsJMYsoz/RUff73yGdurvTx/1nm2ogeLuqTCzEIRhYsK86guUKIvRf8oJj9Vjx3tdVGIh/iLOIjra+K2ITJ9N5MyqsXZZ0H5cXg0r5ekb85VgdgaAoQwdY418p/ritXmrgnvNpto= 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 1787145615153679.1932298357324; Wed, 19 Aug 2026 06:20:15 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wwgCU-0005L6-Bd; Wed, 19 Aug 2026 09:19:26 -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 1wwgCS-0005II-LV for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:24 -0400 Received: from mail-pj1-x102d.google.com ([2607:f8b0:4864:20::102d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wwgCQ-0004sB-DH for qemu-devel@nongnu.org; Wed, 19 Aug 2026 09:19:24 -0400 Received: by mail-pj1-x102d.google.com with SMTP id 98e67ed59e1d1-38e42560ebcso971785a91.1 for ; Wed, 19 Aug 2026 06:19:21 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([156.226.169.41]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3957fb12145sm2734387a91.4.2026.08.19.06.19.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 19 Aug 2026 06:19:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787145561; x=1787750361; 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=5fSJnWphlhlECSW+wv6njLNgjR+jeMC/7N9v4OiIjw0=; b=V6ZPb3752T+LvNqqGK4MfhGU+sc8X6/phqHqqhIIEho+MdpG19Ic5WaRf2YWMH9OE9 9bSnJHjj6KgxgQHlydUvcANlTkMLZWc8wCEcAjBrUQDC1/vHfRuoREzVQvbESMyh33Lh TTEp7L+LVcJI6J0iVyPP3MbZvMibJi8LjNnrH64hHl04J28uJuif7zZTpu1ZbGZHsX4e d5dhJm7c3Nj7AiJ+baMO5Lli4sZmNv4Z0EwW8iqbm+5VebNK9uGzP7qFSgPEF7Tq6QfU 3IZr2ZJKJG1QMMw1QlRVCIP1ohWFsB+5QFn/i3YvLfJyanm3BJ6fd3CMxzHKudtEuurq Z9Qw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787145561; x=1787750361; 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=5fSJnWphlhlECSW+wv6njLNgjR+jeMC/7N9v4OiIjw0=; b=WsuSQcLYOvHSxM7ECgXf+4fjLtk1DYhFlcalRkormybSMcnmvvJKg3FBRdqisZvwtt gKrmP0xhczuz1pjuXREPKtvm0pUCCnMRwP21ymCIimseSvTOeFev7aE8nlePCHOwGVN6 j8byrqX6z/bsHafNqXdLK+rAaGem0LM+OPpHVIgORReurw/LUSAGBQsky3snE4iuPupq 4n70xNkx4KjEPJzB9N6C8wwAVUBMGO+NgajYNQ7A0Kw7XkaoVpB1dTk4IbKslgPgfJEL DustNoD9yPUApjck/I2JSOezXwU58254ZAhEthztwhzfsOMIDJXT2p5uaktlcnhI5gv1 exug== X-Gm-Message-State: AFuF++ma4MLXFajA4kyENrBnSw1TpOuE9ZHVHsX/F2mRozxXratCxowp ytk4+b4gyiSD2UCUKRDkS8Fz9ECxOouWsBXzYzQhAFq0uyA2EoGKZstXw3FABUvet2O2Ag== X-Gm-Gg: AR+sD12gzTsmZ6a1VbZbRCKP2I13rJEOJ/NFxqUsUPxsieDu9lazx+8EYYtv1SpwuYJ hzPyK9EGCZg55kIy3mpuO/C6ZvLY4WDehvyvBLGNLrsTEub0+0+yglDSSe5uXcWxn/Mmk4LLklR 5AXEa3EvRQhnFwCWgeQUhzRBnkx2fLy/HRqiO+kc2MqafJFeaqRNZx5CZBazsYpIJ4ZmhTWvajU iSEwOhsf4rOLAqdc3uoQJepLT/9yFZE95fwd6JPLy5l1INErjX2W7Y0K2KEWtkwigdWuOp4AQIs +0UTkE3vfuExNFPQSVKu3r9Wfh1CK8KCIRvd83I35KY12DjJBIalXmv68qqYf1nTJT2jM8Ip8yT V8gikbQFrchIZ+NSGKQpkBYbg0bROlopQ3MewonXnwETyaNb7kt64/u/PcibSwXMiCqIbBGxZ5p t9kI1nGVknIOSUUDXX8KJlylRp3hDNHVjmBBj1hX7QysVdiQndRwSbHRrZ3pQUQwUJ1yJtxA== X-Received: by 2002:a17:90b:2d05:b0:380:21b7:e727 with SMTP id 98e67ed59e1d1-39581470f03mr8829771a91.14.1787145560919; Wed, 19 Aug 2026 06:19:20 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org, qemu-riscv@nongnu.org Cc: Chao Liu , Alistair Francis , Palmer Dabbelt , Weiwei Li , Daniel Henrique Barboza , Liu Zhiwei , caojunze424 , Bin Meng , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , raoyi Subject: [PATCH v5 3/3] tests/qtest: add k230 dwapb timer test Date: Wed, 19 Aug 2026 21:18:59 +0800 Message-ID: <20260819131859.9583-4-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260819131859.9583-1-rao232328@gmail.com> References: <20260819131859.9583-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::102d; envelope-from=rao232328@gmail.com; helo=mail-pj1-x102d.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: 1787145616493158500 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 | 3 +- 3 files changed, 277 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..01bf03a8b6 --- /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 50000000 + +#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_MASK 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_MASK); + + 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..bacd8719b4 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -297,7 +297,8 @@ 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') ? + ['k230-wdt-test', 'k230-dwapb-timer-test'] : []) =20 qtests_hexagon =3D ['boot-serial-test'] =20 --=20 2.53.0