From nobody Mon Sep 28 00:33:59 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=1786430826; cv=none; d=zohomail.com; s=zohoarc; b=dxaNqiI8jfjQiK6QciR738O6fLilNBkoK+4adh19m7kfO+DU1p3qPBIPaN13t9J+MPMDz+kjwQe0j4clAUo+l00FlEZAsSqYmbfPt7sXZS5MUyVNLilBo5P6E4Qz8zr5kA2Oh9quSx6FJx1Q8Yk4vyBd4fJkpu7NtkPCtdS7JnI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786430826; 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=t5C0Q1+9pQPG2Vh6G3+91uNx+7Cm0WgiqZIEFzKGIUg=; b=ZhW8GvTX/ZUJbUqWZN/RehOuP2Bgk6qotkRvdZcNy6uajm8et67NKvUc+/4Ea4us/su+3XHt2fWon8genxAj0wh5DC1d7WAfamsdw0MhX/sZ7k0uGzKeqb+3jonIRO4FOYsF414sFdeNLg4az6pEJ+Tzq0toocgrWGv1TXghjWI= 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 1786430826341524.5109761032836; Mon, 10 Aug 2026 23:47:06 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wtgGD-0001Bv-1F; Tue, 11 Aug 2026 02:46:53 -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 1wtgGB-0001A1-8s for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:46:51 -0400 Received: from mail-pl1-x636.google.com ([2607:f8b0:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wtgG8-0005MT-13 for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:46:50 -0400 Received: by mail-pl1-x636.google.com with SMTP id d9443c01a7336-2ceab75934dso31280875ad.2 for ; Mon, 10 Aug 2026 23:46:47 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([120.235.190.222]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d315f3ffd5sm2591015ad.30.2026.08.10.23.46.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Aug 2026 23:46:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786430807; x=1787035607; 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=t5C0Q1+9pQPG2Vh6G3+91uNx+7Cm0WgiqZIEFzKGIUg=; b=gKjZgeDshp0F0vX5rH5UbavgYqRbEUc4HLiaF8XbQmxUvTvfaMRAk0dUkSa9GdYbIm CzKYJJE1zKOgLMLa9TCP2T2mUyIKH5QmHsvx+nwMjEEj3rhkfFJHXTMroaxEC2MbBklH O20jakn06h2tq2vz8rCpEuC+0fC39DBCb/bzIYvqUjcD3zFIyDPQojzy3kSVUvucjop1 UcScqotSm9PT8yvUidySanF2tbI8UAi3D5bR9wBNKJ54j+/kKAHZzgYN0WNlec2sOhp2 r4+BzpNKX3R6p5yNFQqmKtJsPDVe9HomQAWS3BKjVDyYFtzga9GL4d4nsO0zTFYtl5JP iScQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786430807; x=1787035607; 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=t5C0Q1+9pQPG2Vh6G3+91uNx+7Cm0WgiqZIEFzKGIUg=; b=ZOURXsiAPTX9Jgaz9da79qKzDmZMWv5LBJ5Urbw8Qa9Yx25wpTrw3oitO3ix9XiSwo EA60ZaAm4ins6FEAGkPrQR0mxXxMfFyRshLXwGzfS775q+O0/jGvLUi1LvLozM0LqYiz lHimUmrwztuAmSlVo4Gts8T4P2ny541wpo2wlk3/KBxV9TrliWFHuM79jmXaIMW5Bj+F hxVz4zSmVIcsVsr3QqmZhdx8rV5RKM0RjNskHMmZEc5gNJ90K8q+Da84Gyd5MQ0UI3eg ZHgm29zK8wn9+Km9K8t1RAC5xyl0nqZVTdIrRVx35DzQLhFLLxqqmRiCLeRs3S+GSyMF Kv/g== X-Gm-Message-State: AOJu0Yy0jF7lzjp294Ng4vRXCMYy+oI1hN8vXaoNlKwuiVP4GxEkdfGb CDpMRDOY6nSatKiFMaj6A+DAfQBaaGqvfBVWBCRkUjYUV+Bvh/8Q5WqAK7kBfhDQ X-Gm-Gg: AR+sD107MVwPg5W4JPIp5Jwqr5G+M686qagwsbXf8h5KREB0/XGq4x/lYgDqlrovaq6 rGlnhyVkiU9Qwqh3nGeaac0uKkucH+W7PQd51L/bSwtRmFVfmxYREduuh/C0eeRYrtgL2o+bARK Dx+3G3H9zviTZ+K9xzT0zPpJl3PTx8m+4Hsgsf0YiPURoitUhpR2XtmnZR8QxBRC3EG6S8pe6Tp GLUt9MoimiC74my4u781c/uzPFkt03CX0o3VtYjcwg3fdXuzhM6QjAd4mNu5LyLTwsH1a4yspCY BCj/qQPdDYmxTcMswi3VeIxX7+zteT8QZw3jdNu8zwl6u37CVdozUgD+yTHg/ja7GwMjjODH9nk P5thBDAPmlk89x/wLdTOPpG4FlM7SUjYRMdoDUfcsk87+SY5YC5D+9ZYEgBz2spFJeRlf3Uy/bw cenO+EI8Gfku2jUNeKSI9v0gLSP+GGdPHDKk/EkAYa+NXCPM3ItidESPEk+R6GWwbnRRc19ojoZ NOj1GbpgFc= X-Received: by 2002:a17:902:ea04:b0:2cf:4c0f:5127 with SMTP id d9443c01a7336-2d3177e7f07mr15079955ad.10.1786430806520; Mon, 10 Aug 2026 23:46:46 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, pbonzini@redhat.com, palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, farosas@suse.de, lvivier@redhat.com, caojunze424@gmail.com, bmeng.cn@gmail.com, raoyi Subject: [PATCH v3 1/3] hw/timer: add DesignWare APB timer model Date: Tue, 11 Aug 2026 14:46:08 +0800 Message-ID: <20260811064612.16517-2-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260811064612.16517-1-rao232328@gmail.com> References: <20260811064612.16517-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::636; envelope-from=rao232328@gmail.com; helo=mail-pl1-x636.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: 1786430828282158500 Content-Type: text/plain; charset="utf-8" Add generic DesignWare APB timer device model. The timer uses the Clock framework for frequency input and supports a configurable number of timer channels via the num-timers property (max 8, default 6). Signed-off-by: raoyi --- hw/timer/Kconfig | 4 + hw/timer/dw-apb-timer.c | 341 ++++++++++++++++++++++++++++++++ hw/timer/meson.build | 1 + hw/timer/trace-events | 8 + include/hw/timer/dw-apb-timer.h | 65 ++++++ 5 files changed, 419 insertions(+) create mode 100644 hw/timer/dw-apb-timer.c create mode 100644 include/hw/timer/dw-apb-timer.h 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..385eff3ba4 --- /dev/null +++ b/hw/timer/dw-apb-timer.c @@ -0,0 +1,341 @@ +/* + * 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" + +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) +{ + 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); + + trace_dw_apb_timer_enable(t->id, t->load); +} + +static void dw_apb_timer_disable(DWAPBTimerChannel *t) +{ + 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); + + trace_dw_apb_timer_disable(t->id); +} + +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; + + addr &=3D 0xfff; + + 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 s->comp_version; + 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); + + addr &=3D 0xfff; + + 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_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_reset(DeviceState *dev) +{ + DWAPBTimerState *s =3D DW_APB_TIMER(dev); + + 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), + DEFINE_PROP_UINT32("comp-version", DWAPBTimerState, comp_version, + 0x3231312A), +}; + +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_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + dc->realize =3D dw_apb_timer_realize; + dc->vmsd =3D &vmstate_dw_apb_timer; + dc->desc =3D "Synopsys DesignWare APB timer"; + device_class_set_legacy_reset(dc, dw_apb_timer_reset); + 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..b08b713fa3 --- /dev/null +++ b/include/hw/timer/dw-apb-timer.h @@ -0,0 +1,65 @@ +/* + * 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 "qemu/bitops.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_MMIO_SIZE 0x100 +#define DW_APB_TIMER_MAX_TIMERS 8 +#define DW_APB_TIMER_STRIDE 0x14 + +/* 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 + +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; + uint32_t comp_version; + DWAPBTimerChannel timers[DW_APB_TIMER_MAX_TIMERS]; +}; + +#endif --=20 2.53.0 From nobody Mon Sep 28 00:33:59 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=1786430851; cv=none; d=zohomail.com; s=zohoarc; b=nbuHJ6R2BDFDJ9FDeSWrD8Yx2hFvqYkJpDNEhb00sgC+56w0mDBdkf0Ud8JXd9tHEaX/l/w0nylgU6EGW5HLBqaVYGEKgWgaEGeZthOHR2APB03gay8fJA4iMXIatyQx2nQ0eEMlD4L382oFM8/JmiCe9exv3YGFFCyacCCVImc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786430851; 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=XL7/RFf7m8h/trUqeMTE/jIbE0eOmEfGvnssk4XnbZI=; b=PGU6o79O8y4drr3PLJnR2NlARR+PjEYGFzK+CYx562OZ1SSi0iHkBQcQNdfD0FFZ/GP4RkWiZCzPvTJxlueYmVj4nhR7v4KjgrScEeFb/xfc12SVcTvGt9sBIrUb0goXzU1tiI7Sz8/PYbrpPhGq3s3WK+jjJnRGzFoyiwk32aA= 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 1786430851755482.2748491710396; Mon, 10 Aug 2026 23:47:31 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wtgGL-0001Kf-J5; Tue, 11 Aug 2026 02:47:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wtgGI-0001Gf-Cc for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:46:59 -0400 Received: from mail-pl1-x62c.google.com ([2607:f8b0:4864:20::62c]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wtgGF-0005Ou-6h for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:46:57 -0400 Received: by mail-pl1-x62c.google.com with SMTP id d9443c01a7336-2cc7ef7ec27so33153115ad.1 for ; Mon, 10 Aug 2026 23:46:53 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([120.235.190.222]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d315f3ffd5sm2591015ad.30.2026.08.10.23.46.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Aug 2026 23:46:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786430812; x=1787035612; 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=XL7/RFf7m8h/trUqeMTE/jIbE0eOmEfGvnssk4XnbZI=; b=Sbq6ycqAtZgTD8vqlwySkmE9+IChJKaFkVXq6VmwJwNIyyZr61BoV7J3KblGhdkL5P g/BwR5KLWj37IoAL+wxgsKva48N+IThMWYNadnA98Qlf9GLf/0dl09Isi/AojTuxKY/V sk1jX91PsPmVFuM14BDGWVUvOuvW/0fsBxZ6VeqO456PYWqaij+BOjARdA+ffQuT8l0o ohWDMG8c/hMXcjm2g81j1ml7JRX+kWzXo2jdAR7SqfS9XwcsT3kG5zKynx1LEjYgy//7 d7mIehtvLyOuBiYc85zN5athlzm7C073/N14YY3i9G3D7dY0Xot9X+LfiR+nxPUccCEH Ll/w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786430812; x=1787035612; 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=XL7/RFf7m8h/trUqeMTE/jIbE0eOmEfGvnssk4XnbZI=; b=ekcSBv/Qk5+5E/U6MBhjqrt1e/nBzDOoZWquWwkY7Jqgk9vRrwRAlOsQT7hcXHGrXr 1y9Rm3oliQSOTWxJNrHbujVJ8dQfij/HXW8vAQuKFKZlCeJfq2dpOGezs00KLrY2HBYp SCNYY53NpKXb1s/UMMBxzc1dAJxSJnkufS+PykTAtw8fZxKariDVpyS43ciZKnJTbIcz 3Wk/VVAoMwmANrmJHFeWG8Av5M5sgY3eJq8wS3gxZLR04RT+7VSJzlyVb9MhIHMH0GCH rpsXx3Mg8pCcXJQae0vlanvol8tvIrAJEQm2Bmh9xhWY+oPiq4VmuvMdVYeHBG5WNDyC zN2w== X-Gm-Message-State: AOJu0YwuUuJy8xleHHFMrYQ2JcPGXM/J/0z840luxdb38e3kB2pAfbMe x507c/brRofuDChIhe+42Lsps9nY4hDI8/1d4FqTlu6Z49i0/gbUTc/KQFFfiqov X-Gm-Gg: AR+sD12xth7FIJqO7Z8xQivWBJ/75rhF1Tzb4a0salC1zhbO8j9nQwGHktl3yBF5oSJ te1qH7s18PQHIOQsUjMOWNXusU2Wdu8bf28UXb0tMhUHuVLU72O16JTpgmsgHtFJ13zuAJcoO9P +uM3NVVXyr6BsaIzY63XuiL92aFhG69W6Rh2Mbwi11oj59Onu/s0H9QTc5BKR1L30ym1c9mz9Dc cawK9Q9vC89A0/G5fYqav0NXi0V9zO3Muxv+9Nwnx9ZD09MDwCPjHFQA5J+KICv7NbR6t5uzR3V ddwPMO+Un9BliQeE16HS+XCy+SAgNkcNPVu6ltvdAp08pQaUrnNhk/eNYCrCSOKMPECj9VdfSSJ 5CLuoutiE/LNDBI3tXWhP0r9Qo2yX5prytHMJEf4EV7e4EnkFzwhj5Rvzl9Rf0Aoj0xUwVvEi6K X8FzLSz8Apkfav3jsHVFhsz39tHpqay84JiCVsQ2TOyHziStPMQw31BJeA08Cl7PwVs0e4MBnU X-Received: by 2002:a17:902:fc4c:b0:2d0:4021:bb6b with SMTP id d9443c01a7336-2d3175f7523mr16659675ad.0.1786430812075; Mon, 10 Aug 2026 23:46:52 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, pbonzini@redhat.com, palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, farosas@suse.de, lvivier@redhat.com, caojunze424@gmail.com, bmeng.cn@gmail.com, raoyi Subject: [PATCH v3 2/3] hw/riscv: add DesignWare APB timer to K230 board Date: Tue, 11 Aug 2026 14:46:09 +0800 Message-ID: <20260811064612.16517-3-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260811064612.16517-1-rao232328@gmail.com> References: <20260811064612.16517-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::62c; envelope-from=rao232328@gmail.com; helo=mail-pl1-x62c.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: 1786430854057158500 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 Reviewed-by: Philippe Mathieu-Daud=C3=A9 --- hw/riscv/Kconfig | 1 + hw/riscv/k230.c | 32 +++++++++++++++++++++++++++++--- include/hw/riscv/k230.h | 12 ++++++++++++ 3 files changed, 42 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..a3457e79ff 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" @@ -110,6 +112,21 @@ 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); + qdev_prop_set_uint32(DEVICE(&s->timer), "comp-version", + K230_TIMER_COMP_VERSION); + + 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 +208,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 +312,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..0f872554c8 100644 --- a/include/hw/riscv/k230.h +++ b/include/hw/riscv/k230.h @@ -18,9 +18,14 @@ #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 +#define K230_TIMER_NUM_CHANNELS 6 +#define K230_TIMER_DEFAULT_FREQ 6250000 +#define K230_TIMER_COMP_VERSION 0x3231312A + #define TYPE_RISCV_K230_SOC "riscv.k230.soc" #define RISCV_K230_SOC(obj) \ OBJECT_CHECK(K230SoCState, (obj), TYPE_RISCV_K230_SOC) @@ -33,6 +38,7 @@ typedef struct K230SoCState { RISCVHartArrayState c908_cpu; /* Small core */ =20 K230WdtState wdt[2]; + DWAPBTimerState timer; MemoryRegion sram; MemoryRegion bootrom; =20 @@ -127,6 +133,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:33:59 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=1786430863; cv=none; d=zohomail.com; s=zohoarc; b=iBsFnS6KH06ONcKgmT+NyvFD3LKNu4FHKY9meuYQ4FjtqSLKtZmmYXJzLflhbNxbhXudp8xQfXHXUhXEgd3ZXQZeNHu+HkgA2brfaxzpN1t3p0KbbQR+7RGT+ez4mHgcsWdzhFXisGDevA4tsEBWIyITFgdK16M8SRMNYSSmIzY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1786430863; 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=r/3tunvNDh+d2dbLfwBToYPitzpMWQNF1ejrM3C3nhg=; b=JyPd+/NJ6M/tRbQmYor4QglQnjw4q0AseO/oFghpZG6CEacxxyEEfgWAVzXWpMNS3TDc4JPq/ylEghblzHn3S4iPZabIAHHA76Jgu9RJcugV1jbGEXRUlc6UuQsi5YFef20x4jLLbUAPc+GDoCLjB6O5JvZf/o2x83f2olstiFA= 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 1786430863712393.08587229933573; Mon, 10 Aug 2026 23:47:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wtgGN-0001Rn-E3; Tue, 11 Aug 2026 02:47:03 -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 1wtgGK-0001Ig-Aj for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:47:01 -0400 Received: from mail-pl1-x630.google.com ([2607:f8b0:4864:20::630]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1wtgGI-0005Q8-5Y for qemu-devel@nongnu.org; Tue, 11 Aug 2026 02:47:00 -0400 Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-2d01663d816so23813635ad.1 for ; Mon, 10 Aug 2026 23:46:57 -0700 (PDT) Received: from DESKTOP-DFGP8OG.lan ([120.235.190.222]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d315f3ffd5sm2591015ad.30.2026.08.10.23.46.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 10 Aug 2026 23:46:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786430816; x=1787035616; 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=r/3tunvNDh+d2dbLfwBToYPitzpMWQNF1ejrM3C3nhg=; b=cogdzkGMIUUqh8d3LoQ86h5UeSYaZdR0Tw7Q+uNiG2kdv/bJt3rK+MO62jXihfu/Tm R8MbOkkb0CeQTjgKDgnUwhbbhPV+e610LGBp/F0FngZT2tRU5TuLMh3zPbm5zvcBK78o u+lDX+Dcf8EPtGzpfk2ZFcDHAEWzgDf+HctQ2SC1YlkxoljdGu0wBMTK675Pcx4vHmRh dQaMzc6USNNj5B3wME4gjr2gM8T5rCEgqDcdq+Co+q2PqTSKmfN4LHzWsDJ1ADPLm5yn 0MOLgBb7MSyQgRuPPw2UJtXquEPPxS8aXXRqOi3OCiVlzUon7O4MVdAD441V98YSIyo/ OSvw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786430816; x=1787035616; 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=r/3tunvNDh+d2dbLfwBToYPitzpMWQNF1ejrM3C3nhg=; b=Cq3TEi/UdgjgYUh9cRMrW0RT125yVegAS/bx0WXNwowKsd/bNrWxU/FgczgHJ3GH2j pWngUtaHXeQsOy8oMn0ZJADfW0F1BzDbpvIbpmYge7Knw8W1pgVNRN9JbLWmlDNJhSJM J6Q+IksJzwCSgTIb+gLWKFL7qzGN/TGpVhPz0MCzrwYWxy0B9jUJOItgX29Pxt3XlDJ9 p1/YUFOx+jV1/9syKBulXmnSQSLzQZFljUcQP1owPVH3b+L7YeuoFIdPyGzEY5JW4OjB P5ZXHl0CKN5JG1Ha6fR5woj4qmOEZE0dvZ0nF8bZNVWnSrVf6CSaF37N9QR2q2NnKswq nRUw== X-Gm-Message-State: AOJu0Yy6u/t9tLta8BLkS1ldGvHSfernxr6KVmLmmLOQlwIjHjH3Kkj6 vSnFhpbP3yVC3iW4H9Ku6+rRALxWR8XNEQsliMlHD0zDrzVFX2hn5u8y9CtiCSKn X-Gm-Gg: AR+sD133+VrncSODpJrM/aEXRHckFfEznSb3p3NwONTbb8MZmPn3B0BU63c3R9U17em 0o2aw5CeFKH0e/D5mLGlzoKVYh//ceIe5TK5vP8p7J4kKNHLKRcjDnEQRCE4+X3O2E/HVqsyJU0 CplBXRIsplQlAXZ/y2dXG+a7AQWmBZC1xnYpCXaipH1wAlxm/wUNe4YunK6Bppg0CxfieZ2eYH+ GiiWNNfHDV5CYg307047hvd/zMu8WDVDBFctbTV2JMxEnHEaRlkQzi6YjajwS6NaqbRKBemQf7z WQOz6pcixu7I1fwGRmdtNRrppoN8RiVc9ewWddYzrr54dU8T8r0Sx70NeRBr6CCY4+a0Oq2Gj36 KybCM/8JvXSyggWNKZyCnYR2R1Z9AoPKgRdtMUP+dqhinyYbiQ33Q052JrNJdyQEcQsQkM9UCeS vQK0L2NdQLVs3JxPDZmi/LR0tudQD5YDQjJ7Hsey7FajvftdJF4OxhsBtq0MvuFETUF3OyLPZC X-Received: by 2002:a17:903:3248:b0:2c9:8f4a:90b with SMTP id d9443c01a7336-2d31776bf4emr16642285ad.3.1786430816422; Mon, 10 Aug 2026 23:46:56 -0700 (PDT) From: raoyi To: qemu-devel@nongnu.org Cc: qemu-riscv@nongnu.org, pbonzini@redhat.com, palmer@dabbelt.com, alistair.francis@wdc.com, liwei1518@gmail.com, daniel.barboza@oss.qualcomm.com, zhiwei_liu@linux.alibaba.com, chao.liu@processmission.com, farosas@suse.de, lvivier@redhat.com, caojunze424@gmail.com, bmeng.cn@gmail.com, raoyi Subject: [PATCH v3 3/3] tests/qtest: add k230 dwapb timer test Date: Tue, 11 Aug 2026 14:46:10 +0800 Message-ID: <20260811064612.16517-4-rao232328@gmail.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260811064612.16517-1-rao232328@gmail.com> References: <20260811064612.16517-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::630; envelope-from=rao232328@gmail.com; helo=mail-pl1-x630.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: 1786430866543158500 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 files to MAINTAINERS. Signed-off-by: raoyi --- MAINTAINERS | 3 + tests/qtest/k230-dwapb-timer-test.c | 261 ++++++++++++++++++++++++++++ tests/qtest/meson.build | 4 +- 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 tests/qtest/k230-dwapb-timer-test.c diff --git a/MAINTAINERS b/MAINTAINERS index 6171cc7494..b30bcba640 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1826,9 +1826,12 @@ 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 +F: tests/qtest/dw-apb-timer-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..70dc384bfa --- /dev/null +++ b/tests/qtest/k230-dwapb-timer-test.c @@ -0,0 +1,261 @@ +/* + * 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" +#include "hw/timer/dw-apb-timer.h" + +#define TIMER_BASE 0x91105800 +#define K230_TIMER_NUM_CHANNELS 6 +#define K230_TIMER_DEFAULT_FREQ 6250000 +#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) =E2=80=94 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