From patchwork Tue Mar 18 13:07:53 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Corvin_K=C3=B6hne?= X-Patchwork-Id: 14020979 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C7882C28B28 for ; Tue, 18 Mar 2025 13:10:58 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tuWho-00072W-3u; Tue, 18 Mar 2025 09:10:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tuWh3-0006Ro-Ve; Tue, 18 Mar 2025 09:09:23 -0400 Received: from mail-ej1-x631.google.com ([2a00:1450:4864:20::631]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tuWh1-0003B6-Ck; Tue, 18 Mar 2025 09:09:17 -0400 Received: by mail-ej1-x631.google.com with SMTP id a640c23a62f3a-ac25d2b2354so956144366b.1; Tue, 18 Mar 2025 06:09:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1742303353; x=1742908153; 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; bh=xSqhzaN+M9hdNsbBzriOUGWRrnB6G7MJ7OrsPut7pwk=; b=JIter+l3AchIETleV+OG7GmB28f9PThHGIOD7nKSK5SkfibsDh3sCBj2X2sS9DpYbN /nmMhBl6r5KKU8YrlNT6XaeRta6eYw9Wgyjy6wMTJV+ReO02M6Un6WZMhMEZfHjmbqGS TeWuyOz7uYYoxSd5UQ6/8f5jjYvV/Q9QbATt4RIbp4C3lFphXRqsOsAW2WCcbcHuC2kx ATHLcMQ/QhFsMGtHET/jXXvHYwRmoB3OJUjqzCxpns8zgifzRc+PeUowWndf4rEq2EdI LXVQQ2jyMnqg/bzc7wo09nv+PsvosUZd1q3vVY/5gz65hL840el5mCD08SvT4bxsy+Oa kaTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742303353; x=1742908153; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xSqhzaN+M9hdNsbBzriOUGWRrnB6G7MJ7OrsPut7pwk=; b=GicRI1q2YROdOKVnTMf7uPBhdSsQ/cjHrYLy8h4mJVcHulk1N41dDmC1QGNaVoQ5yk P6r1g/V/oAd0ufPq2P5I/Gq/6usF5O/eWHYvSveGduAr2onmnUHb51ZucEDE8LNn0nSf rCqxtTTAslkbRmZ/4XxSS7PFDprwFr7zCtceH5m7hdOfbr/RMD13FqpyAtd/AD8SmwTn WONEGgRHckUn9UZDRYl4a7tLpTQZEcZKix7Xcl02y69nNFSfysyxGswDGB6+5cer1+fo O06lj8WpMwuN3FpUJuX3PxXthJZfdyCD02JVsdfLnMtDOSWKPZhExeBIpUWxpjEI6WRf Be9g== X-Forwarded-Encrypted: i=1; AJvYcCXkKFOIIWCgBLU33P6o/0eHLlU3kwBRyyMeb/t07NwPX7+McOYcJi7tKZKxZqn3iluSGK1XNLYTQw==@nongnu.org X-Gm-Message-State: AOJu0YyfxR5OmULA9J3rXWvrEa2IQ+0GwMKgSr4KWPgrdTnGewi/doCU yy9q3FJgpEH2TNZ/P5NH8fdhEO4D474EYdKBRyx/G1WSEiu1tFlh7qAuLf9/ X-Gm-Gg: ASbGncsANJrXAcdL0tT2JGAYSTxjrOQYuA2B/b9v7I8EI1YRn89yDt4HxYD1SsPo1Ut Qb0Web9mNhlAhzjoA3rnpp+kz3DowsBIb+016NpA8unp9BkR64HXkYPeuIIAZ9XG2VHOXNVlIVG dGQ7zxxLItVlI3K0ouwIfLyWaHAUCTFzWTuGIhnh1UtYOwCpdx1wJt9wnCFBSqJWrkNq8c0G8aA L8zn0xoqA65u4XQTTdcW/2hioQQ6WQzA5EsMTA9WNQGDNV8wRAyJQ8u/SCIxfc2iFIFcrNRTJk5 i5clT8/8qRn7Uctzjd3tdl99hFTnJPr5pBzxN8rxjizifkPnxcxm0uFt55wT+7czPYo= X-Google-Smtp-Source: AGHT+IFV5Fk2KtlA54F4IdB0wl0hXoN/YP2bAza4Zc5oy8tbYdixl24f+aM8TGdNnpt1gQI1or2JtA== X-Received: by 2002:a17:907:9495:b0:abe:c81a:985d with SMTP id a640c23a62f3a-ac3304d6112mr1439830366b.48.1742303342285; Tue, 18 Mar 2025 06:09:02 -0700 (PDT) Received: from corvink-nb.beckhoff.com ([195.226.174.194]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-ac3147f3101sm850678066b.69.2025.03.18.06.08.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Mar 2025 06:08:59 -0700 (PDT) From: =?utf-8?q?Corvin_K=C3=B6hne?= To: qemu-devel@nongnu.org, qemu-arm@nongnu.org Cc: =?utf-8?q?Yannick_Vo=C3=9Fen?= , "Edgar E. Iglesias" , Peter Maydell , Alistair Francis , =?utf-8?q?Corvin_K=C3=B6hne?= , Paolo Bonzini , YannickV Subject: [PATCH 02/21] hw/timer: Make PERIPHCLK period configurable Date: Tue, 18 Mar 2025 14:07:53 +0100 Message-ID: <20250318130817.119636-3-corvin.koehne@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250318130817.119636-1-corvin.koehne@gmail.com> References: <20250318130817.119636-1-corvin.koehne@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::631; envelope-from=corvin.koehne@gmail.com; helo=mail-ej1-x631.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 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_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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org From: YannickV The a9 global timer and arm mp timer rely on the PERIPHCLK as their clock source. The period of PERIPHCLK (denoted as N) must be a multiple of the core CLK period, with N being equal to or greater than two. However, the current implementation does not take the PERIPHCLK period into account, leading to unexpected behavior in systems where the application assumes PERIPHCLK is clocked differently. The property periphclk-period represents the period N, the CLK is devided by to get the peripheral clock PERIPHCLK. We can now configure clock properties for the a9 global timer and arm mp timer. That ensures timers can behave according to the applications needs. The PERIPHCLK period can also be set via the command line, for example for the a9 global timer: -global driver=arm.cortex-a9-global-timer, property=periphclk-period,value=2 Information can be found in the Zynq 7000 Soc Technical Reference Manual under Timers. https://docs.amd.com/r/en-US/ug585-zynq-7000-SoC-TRM Signed-off-by: Yannick Voßen --- hw/timer/a9gtimer.c | 19 ++++++++++++++++++- hw/timer/arm_mptimer.c | 20 +++++++++++++++++++- include/hw/timer/a9gtimer.h | 1 + include/hw/timer/arm_mptimer.h | 2 ++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index a1f5540e75..83aa75889e 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -27,6 +27,7 @@ #include "hw/timer/a9gtimer.h" #include "migration/vmstate.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "qemu/timer.h" #include "qemu/bitops.h" #include "qemu/log.h" @@ -62,9 +63,17 @@ static inline int a9_gtimer_get_current_cpu(A9GTimerState *s) static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s) { + /* + * Referring to the ARM-Cortex-A9 MPCore TRM + * + * The a9 global timer relies on the PERIPHCLK as its clock source. + * The PERIPHCLK clock period must be configured as a multiple of the + * main clock CLK. The conversion from the qemu clock (1GHz) to a9 + * gtimer ticks can be calculated like this: + */ uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT, R_CONTROL_PRESCALER_LEN) + 1; - uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10; + uint64_t ret = NANOSECONDS_PER_SECOND * prescale * s->periphclk_period; return (uint32_t) (ret / s->cpu_clk_freq_hz); } @@ -312,6 +321,12 @@ static void a9_gtimer_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s); + if (s->periphclk_period < 2) { + error_report("Invalid periphclk-period (%lu), must be >= 2", + s->periphclk_period); + exit(1); + } + for (i = 0; i < s->num_cpu; i++) { A9GTimerPerCPU *gtb = &s->per_cpu[i]; @@ -377,6 +392,8 @@ static const Property a9_gtimer_properties[] = { DEFINE_PROP_UINT64("cpu-freq", A9GTimerState, cpu_clk_freq_hz, NANOSECONDS_PER_SECOND), DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0), + DEFINE_PROP_UINT64("periphclk-period", A9GTimerState, + periphclk_period, 10), }; static void a9_gtimer_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index a748b6ab1a..767413c77a 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -27,6 +27,7 @@ #include "hw/timer/arm_mptimer.h" #include "migration/vmstate.h" #include "qapi/error.h" +#include "qemu/error-report.h" #include "qemu/module.h" #include "hw/core/cpu.h" @@ -61,8 +62,16 @@ static inline void timerblock_update_irq(TimerBlock *tb) /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ static inline uint32_t timerblock_scale(TimerBlock *tb, uint32_t control) { + /* + * Referring to the ARM-Cortex-A9 MPCore TRM + * + * The arm mp timer relies on the PERIPHCLK as its clock source. + * The PERIPHCLK clock period must be configured as a multiple of the + * main clock CLK. The conversion from the qemu clock (1GHz) to arm mp + * timer ticks can be calculated like this: + */ uint64_t prescale = (((control >> 8) & 0xff) + 1); - uint64_t ret = NANOSECONDS_PER_SECOND * prescale * 10; + uint64_t ret = NANOSECONDS_PER_SECOND * prescale * tb->periphclk_period; return (uint32_t) (ret / tb->freq_hz); } @@ -273,6 +282,12 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { TimerBlock *tb = &s->timerblock[i]; tb->freq_hz = s->clk_freq_hz; + if (s->periphclk_period < 2) { + error_report("Invalid periphclk-period (%lu), must be >= 2", + s->periphclk_period); + exit(1); + } + tb->periphclk_period = s->periphclk_period; tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY); sysbus_init_irq(sbd, &tb->irq); memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, @@ -288,6 +303,7 @@ static const VMStateDescription vmstate_timerblock = { .fields = (const VMStateField[]) { VMSTATE_UINT32(control, TimerBlock), VMSTATE_UINT64(freq_hz, TimerBlock), + VMSTATE_UINT64(periphclk_period, TimerBlock), VMSTATE_UINT32(status, TimerBlock), VMSTATE_PTIMER(timer, TimerBlock), VMSTATE_END_OF_LIST() @@ -309,6 +325,8 @@ static const Property arm_mptimer_properties[] = { DEFINE_PROP_UINT64("clk-freq", ARMMPTimerState, clk_freq_hz, NANOSECONDS_PER_SECOND), DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), + DEFINE_PROP_UINT64("periphclk-period", ARMMPTimerState, + periphclk_period, 10), }; static void arm_mptimer_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/timer/a9gtimer.h b/include/hw/timer/a9gtimer.h index 8ce507a793..edb51f91e3 100644 --- a/include/hw/timer/a9gtimer.h +++ b/include/hw/timer/a9gtimer.h @@ -77,6 +77,7 @@ struct A9GTimerState { MemoryRegion iomem; /* static props */ uint64_t cpu_clk_freq_hz; + uint64_t periphclk_period; uint32_t num_cpu; QEMUTimer *timer; diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h index 8b936cceac..2c4cb5c1c3 100644 --- a/include/hw/timer/arm_mptimer.h +++ b/include/hw/timer/arm_mptimer.h @@ -32,6 +32,7 @@ typedef struct { uint32_t status; struct ptimer_state *timer; uint64_t freq_hz; + uint64_t periphclk_period; qemu_irq irq; MemoryRegion iomem; } TimerBlock; @@ -45,6 +46,7 @@ struct ARMMPTimerState { /*< public >*/ uint64_t clk_freq_hz; + uint64_t periphclk_period; uint32_t num_cpu; TimerBlock timerblock[ARM_MPTIMER_MAX_CPUS]; MemoryRegion iomem;