From nobody Sat Oct 4 15:57:19 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4C94239072; Thu, 14 Aug 2025 15:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186388; cv=none; b=mNUeyVwHjnbsmA+VmC25K/L7II3yJiLzuJhxA1MQlvhchhSl/wZ1k/MbY7MqTMDVDfEwjmz3AFVT8HNswxWBjfuK01LQNOoGFJlKDAqEs5Ns4745ROzCwY04GBQh+yjyxGcnt5wBImHxePaC45Sk7RvTf9z+STspm7HwuCC2gw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186388; c=relaxed/simple; bh=vgKNO9KMKM8wBYx2jsyzSgi+p35j799z+r40TDqKnfM=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=F0s5eeVzOZrm6DcENxyQ2m9cfb0UTqMrm1gaa67LoAbjkUs7qwFFXNPvkc7bWrAFF6w2GFVXJUSB06+2+Rj6UEAVe6J43MJvlGPFYi6kLgRZIQX/UWdDy7ORyvmkxXcIfWHIVXVoJN+OJnHb2Wg5bb4FIB0bY5j7lQdUBfzqolo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jr50G62H; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jr50G62H" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2BFB1C4CEEF; Thu, 14 Aug 2025 15:46:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755186388; bh=vgKNO9KMKM8wBYx2jsyzSgi+p35j799z+r40TDqKnfM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jr50G62H1Qx9CHSo0nMhM7RMBO9Uw6ApNxLok7rtAUSGkBwZ+JhCsnpYGVJRtHPvM NnLKi5V0XyhSxRWo1/MqhhHRggOgfi2HRkVxD0QR8f1W1zrGkcc/NBV25d4NHzjd2k MHiTlN8dc7WzXm81tD/nYXEIKVJbgq17C9rQ96Xc/+UwXheHmA+JQCrvZGGYW4QXI3 XLgjtECPozalHMeOGvLIIa+Y/GziVCIuEqS9I5iHEzObHll/blbvk6dD8bvcJPIjHI ibywTtkmMtz1bF4kGaRZwPZobJbetf6q9xhssw5zeSEpSgj9pEdXBeBY8zDDoQw6+a 2AkCgiRl2uHzA== Received: from sofa.misterjones.org ([185.219.108.64] helo=valley-girl.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1uma9p-007VqB-Qx; Thu, 14 Aug 2025 16:46:25 +0100 From: Marc Zyngier To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Lorenzo Pieralisi , Hanjun Guo , Sudeep Holla , "Rafael J. Wysocki" , Daniel Lezcano , Thomas Gleixner , Mark Rutland , Alexandru Elisei , Steven Price Subject: [PATCH v2 1/4] ACPI: GTDT: Generate platform devices for MMIO timers Date: Thu, 14 Aug 2025 16:46:19 +0100 Message-Id: <20250814154622.10193-2-maz@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250814154622.10193-1-maz@kernel.org> References: <20250814154622.10193-1-maz@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, lpieralisi@kernel.org, guohanjun@huawei.com, sudeep.holla@arm.com, rafael@kernel.org, daniel.lezcano@linaro.org, tglx@linutronix.de, mark.rutland@arm.com, alexandru.elisei@arm.com, steven.price@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Content-Type: text/plain; charset="utf-8" In preparation for the MMIO timer support code becoming an actual driver, mimic what is done for the SBSA watchdog and expose a synthetic device for each MMIO timer block. Tested-by: Sudeep Holla Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/20250807160243.1970533-2-maz@kernel.org Signed-off-by: Marc Zyngier --- drivers/acpi/arm64/gtdt.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/arm64/gtdt.c b/drivers/acpi/arm64/gtdt.c index 70f8290b659de..fd995a1d3d248 100644 --- a/drivers/acpi/arm64/gtdt.c +++ b/drivers/acpi/arm64/gtdt.c @@ -388,11 +388,11 @@ static int __init gtdt_import_sbsa_gwdt(struct acpi_g= tdt_watchdog *wd, return 0; } =20 -static int __init gtdt_sbsa_gwdt_init(void) +static int __init gtdt_platform_timer_init(void) { void *platform_timer; struct acpi_table_header *table; - int ret, timer_count, gwdt_count =3D 0; + int ret, timer_count, gwdt_count =3D 0, mmio_timer_count =3D 0; =20 if (acpi_disabled) return 0; @@ -414,20 +414,41 @@ static int __init gtdt_sbsa_gwdt_init(void) goto out_put_gtdt; =20 for_each_platform_timer(platform_timer) { + ret =3D 0; + if (is_non_secure_watchdog(platform_timer)) { ret =3D gtdt_import_sbsa_gwdt(platform_timer, gwdt_count); if (ret) - break; + continue; gwdt_count++; + } else if (is_timer_block(platform_timer)) { + struct arch_timer_mem atm =3D {}; + struct platform_device *pdev; + + ret =3D gtdt_parse_timer_block(platform_timer, &atm); + if (ret) + continue; + + pdev =3D platform_device_register_data(NULL, "gtdt-arm-mmio-timer", + gwdt_count, &atm, + sizeof(atm)); + if (IS_ERR(pdev)) { + pr_err("Can't register timer %d\n", gwdt_count); + continue; + } + + mmio_timer_count++; } } =20 if (gwdt_count) pr_info("found %d SBSA generic Watchdog(s).\n", gwdt_count); + if (mmio_timer_count) + pr_info("found %d Generic MMIO timer(s).\n", mmio_timer_count); =20 out_put_gtdt: acpi_put_table(table); return ret; } =20 -device_initcall(gtdt_sbsa_gwdt_init); +device_initcall(gtdt_platform_timer_init); --=20 2.39.2 From nobody Sat Oct 4 15:57:19 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C88823ABA7; Thu, 14 Aug 2025 15:46:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186389; cv=none; b=f+OKIR4czuMIn29EM/pwHA9a/Vl2hvLEUrC84CkeAxQU2rS1FnIjnXLANY4I/VqU3+o5um4S0ODq+YVZ6X6je3PnpuDsfEzFH/GiuOvcQVh8mMMxQRJxx8umrzydoXHrfcf8Q6Bi1yIqU352WRlKRSyg/1qYNOSKqjWTROIPG6w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186389; c=relaxed/simple; bh=9Jmy1KsNsx9Doph/6jTgxXrZ/A8AtUlSsVBuMvi6qyc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=oJ1DickXBMKq+lIOsqM0sjzjttSKbwUCYFxH6SUHz2a/XJVX7o7EI7aMtXQm9xJsGa0Hb1vPsF8OH7ezFR89kfj/dGycM44mC0FhLcYIR310bkG8kKnae7gen9mG2Oo+WW9txwuN+yfNdOMvd+y7Nnyspk/KgXunEmBEHXgOkms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nlvRCqtC; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nlvRCqtC" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 85509C4CEF1; Thu, 14 Aug 2025 15:46:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755186388; bh=9Jmy1KsNsx9Doph/6jTgxXrZ/A8AtUlSsVBuMvi6qyc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nlvRCqtCJqfnH6yEpl7+eTlTRUd0YTcUhuo341mq/t43LQaHPqzFDH3/SAU7BxlNB ckkDRivLsomi6KHAfBGEYCxuOetf/BSpRomZKwVJPBFhYPsJ/FP9d6bJuZp/3aI5a0 3bHVjc5dC+h47gQSWW6hILDUmgNByjE0ISVP8QM/IVhdeZnRCO4XPg4VpFqNy3U6pS cq9vP4rqzGgUfmo9fFs+GrJ24AAlNl/Tmrv3Fr5HPNzAoQXKutbTkJfX5EA/zw+O0H cKeQ6K+hF6txH7fmhZ/rYn3e50xnnDCPysNcBvdevMarNjWY5hwHPTCeSVmJRk0502 YQ81KOdEIjOGw== Received: from sofa.misterjones.org ([185.219.108.64] helo=valley-girl.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1uma9q-007VqB-3t; Thu, 14 Aug 2025 16:46:26 +0100 From: Marc Zyngier To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Lorenzo Pieralisi , Hanjun Guo , Sudeep Holla , "Rafael J. Wysocki" , Daniel Lezcano , Thomas Gleixner , Mark Rutland , Alexandru Elisei , Steven Price Subject: [PATCH v2 2/4] clocksource/drivers/arm_arch_timer: Add standalone MMIO driver Date: Thu, 14 Aug 2025 16:46:20 +0100 Message-Id: <20250814154622.10193-3-maz@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250814154622.10193-1-maz@kernel.org> References: <20250814154622.10193-1-maz@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, lpieralisi@kernel.org, guohanjun@huawei.com, sudeep.holla@arm.com, rafael@kernel.org, daniel.lezcano@linaro.org, tglx@linutronix.de, mark.rutland@arm.com, alexandru.elisei@arm.com, steven.price@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Content-Type: text/plain; charset="utf-8" Add a new driver for the MMIO side of the ARM architected timer. Most of it has been lifted from the existing arch timer code, massaged, and finally rewritten. It supports both DT and ACPI as firmware descriptions. Tested-by: Sudeep Holla Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/20250807160243.1970533-3-maz@kernel.org Signed-off-by: Marc Zyngier --- MAINTAINERS | 1 + drivers/clocksource/arm_arch_timer_mmio.c | 421 ++++++++++++++++++++++ 2 files changed, 422 insertions(+) create mode 100644 drivers/clocksource/arm_arch_timer_mmio.c diff --git a/MAINTAINERS b/MAINTAINERS index fe168477caa45..2243b726edd7e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1990,6 +1990,7 @@ S: Maintained F: arch/arm/include/asm/arch_timer.h F: arch/arm64/include/asm/arch_timer.h F: drivers/clocksource/arm_arch_timer.c +F: drivers/clocksource/arm_arch_timer_mmio.c =20 ARM GENERIC INTERRUPT CONTROLLER DRIVERS M: Marc Zyngier diff --git a/drivers/clocksource/arm_arch_timer_mmio.c b/drivers/clocksourc= e/arm_arch_timer_mmio.c new file mode 100644 index 0000000000000..3522d1d8cb97b --- /dev/null +++ b/drivers/clocksource/arm_arch_timer_mmio.c @@ -0,0 +1,421 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ARM Generic Memory Mapped Timer support + * + * Split from drivers/clocksource/arm_arch_timer.c + * + * Copyright (C) 2011 ARM Ltd. + * All Rights Reserved + */ + +#define pr_fmt(fmt) "arch_timer_mmio: " fmt + +#include +#include +#include +#include +#include +#include + +#include + +#define CNTTIDR 0x08 +#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) + +#define CNTACR(n) (0x40 + ((n) * 4)) +#define CNTACR_RPCT BIT(0) +#define CNTACR_RVCT BIT(1) +#define CNTACR_RFRQ BIT(2) +#define CNTACR_RVOFF BIT(3) +#define CNTACR_RWVT BIT(4) +#define CNTACR_RWPT BIT(5) + +#define CNTPCT_LO 0x00 +#define CNTVCT_LO 0x08 +#define CNTFRQ 0x10 +#define CNTP_CVAL_LO 0x20 +#define CNTP_CTL 0x2c +#define CNTV_CVAL_LO 0x30 +#define CNTV_CTL 0x3c + +enum arch_timer_access { + PHYS_ACCESS, + VIRT_ACCESS, +}; + +struct arch_timer { + struct clock_event_device evt; + struct arch_timer_mem *gt_block; + void __iomem *base; + enum arch_timer_access access; + u32 rate; +}; + +#define evt_to_arch_timer(e) container_of(e, struct arch_timer, evt) + +static void arch_timer_mmio_write(struct arch_timer *timer, + enum arch_timer_reg reg, u64 val) +{ + switch (timer->access) { + case PHYS_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed((u32)val, timer->base + CNTP_CTL); + return; + case ARCH_TIMER_REG_CVAL: + /* + * Not guaranteed to be atomic, so the timer + * must be disabled at this point. + */ + writeq_relaxed(val, timer->base + CNTP_CVAL_LO); + return; + } + break; + case VIRT_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + writel_relaxed((u32)val, timer->base + CNTV_CTL); + return; + case ARCH_TIMER_REG_CVAL: + /* Same restriction as above */ + writeq_relaxed(val, timer->base + CNTV_CVAL_LO); + return; + } + break; + } + + /* Should never be here */ + WARN_ON_ONCE(1); +} + +static u32 arch_timer_mmio_read(struct arch_timer *timer, enum arch_timer_= reg reg) +{ + switch (timer->access) { + case PHYS_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + return readl_relaxed(timer->base + CNTP_CTL); + default: + break; + } + break; + case VIRT_ACCESS: + switch (reg) { + case ARCH_TIMER_REG_CTRL: + return readl_relaxed(timer->base + CNTV_CTL); + default: + break; + } + break; + } + + /* Should never be here */ + WARN_ON_ONCE(1); + return 0; +} + +static noinstr u64 arch_counter_mmio_get_cnt(struct arch_timer *t) +{ + int offset_lo =3D t->access =3D=3D VIRT_ACCESS ? CNTVCT_LO : CNTPCT_LO; + u32 cnt_lo, cnt_hi, tmp_hi; + + do { + cnt_hi =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= + 4)); + cnt_lo =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= )); + tmp_hi =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= + 4)); + } while (cnt_hi !=3D tmp_hi); + + return ((u64) cnt_hi << 32) | cnt_lo; +} + +static int arch_timer_mmio_shutdown(struct clock_event_device *clk) +{ + struct arch_timer *at =3D evt_to_arch_timer(clk); + unsigned long ctrl; + + ctrl =3D arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL); + ctrl &=3D ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl); + + return 0; +} + +static int arch_timer_mmio_set_next_event(unsigned long evt, + struct clock_event_device *clk) +{ + struct arch_timer *timer =3D evt_to_arch_timer(clk); + unsigned long ctrl; + u64 cnt; + + ctrl =3D arch_timer_mmio_read(timer, ARCH_TIMER_REG_CTRL); + + /* Timer must be disabled before programming CVAL */ + if (ctrl & ARCH_TIMER_CTRL_ENABLE) { + ctrl &=3D ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl); + } + + ctrl |=3D ARCH_TIMER_CTRL_ENABLE; + ctrl &=3D ~ARCH_TIMER_CTRL_IT_MASK; + + cnt =3D arch_counter_mmio_get_cnt(timer); + + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CVAL, evt + cnt); + arch_timer_mmio_write(timer, ARCH_TIMER_REG_CTRL, ctrl); + return 0; +} + +static irqreturn_t arch_timer_mmio_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt =3D dev_id; + struct arch_timer *at =3D evt_to_arch_timer(evt); + unsigned long ctrl; + + ctrl =3D arch_timer_mmio_read(at, ARCH_TIMER_REG_CTRL); + if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { + ctrl |=3D ARCH_TIMER_CTRL_IT_MASK; + arch_timer_mmio_write(at, ARCH_TIMER_REG_CTRL, ctrl); + evt->event_handler(evt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static struct arch_timer_mem_frame *find_best_frame(struct platform_device= *pdev) +{ + struct arch_timer_mem_frame *frame, *best_frame =3D NULL; + struct arch_timer *at =3D platform_get_drvdata(pdev); + void __iomem *cntctlbase; + u32 cnttidr; + + cntctlbase =3D ioremap(at->gt_block->cntctlbase, at->gt_block->size); + if (!cntctlbase) { + dev_err(&pdev->dev, "Can't map CNTCTLBase @ %pa\n", + &at->gt_block->cntctlbase); + return NULL; + } + + cnttidr =3D readl_relaxed(cntctlbase + CNTTIDR); + + /* + * Try to find a virtual capable frame. Otherwise fall back to a + * physical capable frame. + */ + for (int i =3D 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { + u32 cntacr =3D CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | + CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; + + frame =3D &at->gt_block->frame[i]; + if (!frame->valid) + continue; + + /* Try enabling everything, and see what sticks */ + writel_relaxed(cntacr, cntctlbase + CNTACR(i)); + cntacr =3D readl_relaxed(cntctlbase + CNTACR(i)); + + /* Pick a suitable frame for which we have an IRQ */ + if ((cnttidr & CNTTIDR_VIRT(i)) && + !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT)) && + frame->virt_irq) { + best_frame =3D frame; + at->access =3D VIRT_ACCESS; + break; + } + + if ((~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) || + !frame->phys_irq) + continue; + + at->access =3D PHYS_ACCESS; + best_frame =3D frame; + } + + iounmap(cntctlbase); + + return best_frame; +} + +static void arch_timer_mmio_setup(struct arch_timer *at, int irq) +{ + at->evt =3D (struct clock_event_device) { + .features =3D (CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ), + .name =3D "arch_mem_timer", + .rating =3D 400, + .cpumask =3D cpu_possible_mask, + .irq =3D irq, + .set_next_event =3D arch_timer_mmio_set_next_event, + .set_state_oneshot_stopped =3D arch_timer_mmio_shutdown, + .set_state_shutdown =3D arch_timer_mmio_shutdown, + }; + + at->evt.set_state_shutdown(&at->evt); + + clockevents_config_and_register(&at->evt, at->rate, 0xf, + (unsigned long)CLOCKSOURCE_MASK(56)); + + enable_irq(at->evt.irq); +} + +static int arch_timer_mmio_frame_register(struct platform_device *pdev, + struct arch_timer_mem_frame *frame) +{ + struct arch_timer *at =3D platform_get_drvdata(pdev); + struct device_node *np =3D pdev->dev.of_node; + int ret, irq; + u32 rate; + + if (!devm_request_mem_region(&pdev->dev, frame->cntbase, frame->size, + "arch_mem_timer")) + return -EBUSY; + + at->base =3D devm_ioremap(&pdev->dev, frame->cntbase, frame->size); + if (!at->base) { + dev_err(&pdev->dev, "Can't map frame's registers\n"); + return -ENXIO; + } + + /* + * Allow "clock-frequency" to override the probed rate. If neither + * lead to something useful, use the CPU timer frequency as the + * fallback. The nice thing about that last point is that we woudn't + * made it here if we didn't have a valid frequency. + */ + rate =3D readl_relaxed(at->base + CNTFRQ); + + if (!np || of_property_read_u32(np, "clock-frequency", &at->rate)) + at->rate =3D rate; + + if (!at->rate) + at->rate =3D arch_timer_get_rate(); + + irq =3D at->access =3D=3D VIRT_ACCESS ? frame->virt_irq : frame->phys_irq; + ret =3D devm_request_irq(&pdev->dev, irq, arch_timer_mmio_handler, + IRQF_TIMER | IRQF_NO_AUTOEN, "arch_mem_timer", + &at->evt); + if (ret) { + dev_err(&pdev->dev, "Failed to request mem timer irq\n"); + return ret; + } + + /* Afer this point, we're not allowed to fail anymore */ + arch_timer_mmio_setup(at, irq); + return 0; +} + +static int of_populate_gt_block(struct platform_device *pdev, + struct arch_timer *at) +{ + struct resource res; + + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) + return -EINVAL; + + at->gt_block->cntctlbase =3D res.start; + at->gt_block->size =3D resource_size(&res); + + for_each_available_child_of_node_scoped(pdev->dev.of_node, frame_node) { + struct arch_timer_mem_frame *frame; + u32 n; + + if (of_property_read_u32(frame_node, "frame-number", &n)) { + dev_err(&pdev->dev, FW_BUG "Missing frame-number\n"); + return -EINVAL; + } + if (n >=3D ARCH_TIMER_MEM_MAX_FRAMES) { + dev_err(&pdev->dev, + FW_BUG "Wrong frame-number, only 0-%u are permitted\n", + ARCH_TIMER_MEM_MAX_FRAMES - 1); + return -EINVAL; + } + + frame =3D &at->gt_block->frame[n]; + + if (frame->valid) { + dev_err(&pdev->dev, FW_BUG "Duplicated frame-number\n"); + return -EINVAL; + } + + if (of_address_to_resource(frame_node, 0, &res)) + return -EINVAL; + + frame->cntbase =3D res.start; + frame->size =3D resource_size(&res); + + frame->phys_irq =3D irq_of_parse_and_map(frame_node, 0); + frame->virt_irq =3D irq_of_parse_and_map(frame_node, 1); + + frame->valid =3D true; + } + + return 0; +} + +static int arch_timer_mmio_probe(struct platform_device *pdev) +{ + struct arch_timer_mem_frame *frame; + struct arch_timer *at; + struct device_node *np; + int ret; + + np =3D pdev->dev.of_node; + + at =3D devm_kmalloc(&pdev->dev, sizeof(*at), GFP_KERNEL | __GFP_ZERO); + if (!at) + return -ENOMEM; + + if (np) { + at->gt_block =3D devm_kmalloc(&pdev->dev, sizeof(*at->gt_block), + GFP_KERNEL | __GFP_ZERO); + if (!at->gt_block) + return -ENOMEM; + ret =3D of_populate_gt_block(pdev, at); + if (ret) + return ret; + } else { + at->gt_block =3D dev_get_platdata(&pdev->dev); + } + + platform_set_drvdata(pdev, at); + + frame =3D find_best_frame(pdev); + if (!frame) { + dev_err(&pdev->dev, + "Unable to find a suitable frame in timer @ %pa\n", + &at->gt_block->cntctlbase); + return -EINVAL; + } + + ret =3D arch_timer_mmio_frame_register(pdev, frame); + if (!ret) + dev_info(&pdev->dev, + "mmio timer running at %lu.%02luMHz (%s)\n", + (unsigned long)at->rate / 1000000, + (unsigned long)(at->rate / 10000) % 100, + at->access =3D=3D VIRT_ACCESS ? "virt" : "phys"); + + return ret; +} + +static const struct of_device_id arch_timer_mmio_of_table[] =3D { + { .compatible =3D "arm,armv7-timer-mem", }, + {} +}; + +static struct platform_driver arch_timer_mmio_drv =3D { + .driver =3D { + .name =3D "arch-timer-mmio", + .of_match_table =3D arch_timer_mmio_of_table, + }, + .probe =3D arch_timer_mmio_probe, +}; +builtin_platform_driver(arch_timer_mmio_drv); + +static struct platform_driver arch_timer_mmio_acpi_drv =3D { + .driver =3D { + .name =3D "gtdt-arm-mmio-timer", + }, + .probe =3D arch_timer_mmio_probe, +}; +builtin_platform_driver(arch_timer_mmio_acpi_drv); --=20 2.39.2 From nobody Sat Oct 4 15:57:19 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EF07E23ABA7; Thu, 14 Aug 2025 15:46:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186399; cv=none; b=nvaLnhNA4rY5LxH9KAIqH1aOm+i4U9V5H6KDy4dNL+mSzinIXZpFQjNAAUOv+1lA8afte4U+79QrHsbHFydz55kg5oKIUOJZTWchu2adX1uX+SN5IG8jzKdHZkUqx72vYvRIQHToUzKAiwBkNe5T/ZjM/hCh50UbkmHo5pZZ+O8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186399; c=relaxed/simple; bh=SAjpOVy06kEe4dcykDne8LUFQAwV23DbrLG2Adv4PZ4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FlRC5651fmHcZFoqxuTdonOIHOGfPufbA3vt6Q5/9LQigDGYXo/Rqx5/Rc7Fan4ut0Y33EZvM1KGs3WoEY9uuGvYk6fBMcWhm96KrpKIfQXnyYZT3cU42b91XnXAkMkMWRYxbR99YJt39R1jrKl/Ua1xT5HBuVo3D1DCZaJWSmM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D6lG4S6l; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D6lG4S6l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 88771C4CEEF; Thu, 14 Aug 2025 15:46:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755186398; bh=SAjpOVy06kEe4dcykDne8LUFQAwV23DbrLG2Adv4PZ4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D6lG4S6l3IG649q/NoniQXmtZ62HDtqnfJ2F8/SDmbM8Kdzx4InqnAvehNt5oPK5d eSPdzicEi8Jh5voDZFSndx47Hb1PJ9Cx+nGjtiG4w/IZSVnOpwbjLIPsGqybZ/glig aop7DPUtGdA1oCAWbRhsERjbV3gwL5aK/mfew0kCis34TDJpvvZFmoVIh4xEqgjJwb McJzB1Y8uuvodwiAAOPjlnc/bTm1QrKUTJwCmj1PtFQlWjW3bE02uO8IfUWXbf9E9r RDvU7j1pv4zgoAWNZ2hfF/BeOh4oZ+d57cqmZ7SfWN2yvyhxuaDXUK4PyFFuqeJEor Q2i9E0JMA/CeQ== Received: from sofa.misterjones.org ([185.219.108.64] helo=valley-girl.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1uma9q-007VqB-GI; Thu, 14 Aug 2025 16:46:26 +0100 From: Marc Zyngier To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Lorenzo Pieralisi , Hanjun Guo , Sudeep Holla , "Rafael J. Wysocki" , Daniel Lezcano , Thomas Gleixner , Mark Rutland , Alexandru Elisei , Steven Price Subject: [PATCH v2 3/4] clocksource/drivers/arm_arch_timer_mmio: Switch over to standalone driver Date: Thu, 14 Aug 2025 16:46:21 +0100 Message-Id: <20250814154622.10193-4-maz@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250814154622.10193-1-maz@kernel.org> References: <20250814154622.10193-1-maz@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, lpieralisi@kernel.org, guohanjun@huawei.com, sudeep.holla@arm.com, rafael@kernel.org, daniel.lezcano@linaro.org, tglx@linutronix.de, mark.rutland@arm.com, alexandru.elisei@arm.com, steven.price@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Content-Type: text/plain; charset="utf-8" Remove all the MMIO support from the per-CPU timer driver, and switch over to the standalove driver. Tested-by: Sudeep Holla Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/20250807160243.1970533-4-maz@kernel.org Signed-off-by: Marc Zyngier --- drivers/clocksource/Makefile | 1 + drivers/clocksource/arm_arch_timer.c | 686 +++------------------------ include/clocksource/arm_arch_timer.h | 5 - 3 files changed, 66 insertions(+), 626 deletions(-) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 205bf3b0a8f3f..0dcd958e21443 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_REALTEK_OTTO_TIMER) +=3D timer-rtl-otto.o =20 obj-$(CONFIG_ARC_TIMERS) +=3D arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) +=3D arm_arch_timer.o +obj-$(CONFIG_ARM_ARCH_TIMER) +=3D arm_arch_timer_mmio.o obj-$(CONFIG_ARM_GLOBAL_TIMER) +=3D arm_global_timer.o obj-$(CONFIG_ARMV7M_SYSTICK) +=3D armv7m_systick.o obj-$(CONFIG_ARM_TIMER_SP804) +=3D timer-sp804.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm= _arch_timer.c index 80ba6a54248c4..90aeff44a2764 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -34,42 +34,12 @@ =20 #include =20 -#define CNTTIDR 0x08 -#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) - -#define CNTACR(n) (0x40 + ((n) * 4)) -#define CNTACR_RPCT BIT(0) -#define CNTACR_RVCT BIT(1) -#define CNTACR_RFRQ BIT(2) -#define CNTACR_RVOFF BIT(3) -#define CNTACR_RWVT BIT(4) -#define CNTACR_RWPT BIT(5) - -#define CNTPCT_LO 0x00 -#define CNTVCT_LO 0x08 -#define CNTFRQ 0x10 -#define CNTP_CVAL_LO 0x20 -#define CNTP_CTL 0x2c -#define CNTV_CVAL_LO 0x30 -#define CNTV_CTL 0x3c - /* * The minimum amount of time a generic counter is guaranteed to not roll = over * (40 years) */ #define MIN_ROLLOVER_SECS (40ULL * 365 * 24 * 3600) =20 -static unsigned arch_timers_present __initdata; - -struct arch_timer { - void __iomem *base; - struct clock_event_device evt; -}; - -static struct arch_timer *arch_timer_mem __ro_after_init; - -#define to_arch_timer(e) container_of(e, struct arch_timer, evt) - static u32 arch_timer_rate __ro_after_init; static int arch_timer_ppi[ARCH_TIMER_MAX_TIMER_PPI] __ro_after_init; =20 @@ -85,7 +55,6 @@ static struct clock_event_device __percpu *arch_timer_evt; =20 static enum arch_timer_ppi_nr arch_timer_uses_ppi __ro_after_init =3D ARCH= _TIMER_VIRT_PPI; static bool arch_timer_c3stop __ro_after_init; -static bool arch_timer_mem_use_virtual __ro_after_init; static bool arch_counter_suspend_stop __ro_after_init; #ifdef CONFIG_GENERIC_GETTIMEOFDAY static enum vdso_clock_mode vdso_default =3D VDSO_CLOCKMODE_ARCHTIMER; @@ -121,76 +90,6 @@ static int arch_counter_get_width(void) /* * Architected system timer support. */ - -static __always_inline -void arch_timer_reg_write(int access, enum arch_timer_reg reg, u64 val, - struct clock_event_device *clk) -{ - if (access =3D=3D ARCH_TIMER_MEM_PHYS_ACCESS) { - struct arch_timer *timer =3D to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - writel_relaxed((u32)val, timer->base + CNTP_CTL); - break; - case ARCH_TIMER_REG_CVAL: - /* - * Not guaranteed to be atomic, so the timer - * must be disabled at this point. - */ - writeq_relaxed(val, timer->base + CNTP_CVAL_LO); - break; - default: - BUILD_BUG(); - } - } else if (access =3D=3D ARCH_TIMER_MEM_VIRT_ACCESS) { - struct arch_timer *timer =3D to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - writel_relaxed((u32)val, timer->base + CNTV_CTL); - break; - case ARCH_TIMER_REG_CVAL: - /* Same restriction as above */ - writeq_relaxed(val, timer->base + CNTV_CVAL_LO); - break; - default: - BUILD_BUG(); - } - } else { - arch_timer_reg_write_cp15(access, reg, val); - } -} - -static __always_inline -u32 arch_timer_reg_read(int access, enum arch_timer_reg reg, - struct clock_event_device *clk) -{ - u32 val; - - if (access =3D=3D ARCH_TIMER_MEM_PHYS_ACCESS) { - struct arch_timer *timer =3D to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - val =3D readl_relaxed(timer->base + CNTP_CTL); - break; - default: - BUILD_BUG(); - } - } else if (access =3D=3D ARCH_TIMER_MEM_VIRT_ACCESS) { - struct arch_timer *timer =3D to_arch_timer(clk); - switch (reg) { - case ARCH_TIMER_REG_CTRL: - val =3D readl_relaxed(timer->base + CNTV_CTL); - break; - default: - BUILD_BUG(); - } - } else { - val =3D arch_timer_reg_read_cp15(access, reg); - } - - return val; -} - static noinstr u64 raw_counter_get_cntpct_stable(void) { return __arch_counter_get_cntpct_stable(); @@ -424,7 +323,7 @@ void erratum_set_next_event_generic(const int access, u= nsigned long evt, unsigned long ctrl; u64 cval; =20 - ctrl =3D arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl =3D arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl |=3D ARCH_TIMER_CTRL_ENABLE; ctrl &=3D ~ARCH_TIMER_CTRL_IT_MASK; =20 @@ -436,7 +335,7 @@ void erratum_set_next_event_generic(const int access, u= nsigned long evt, write_sysreg(cval, cntv_cval_el0); } =20 - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); } =20 static __maybe_unused int erratum_set_next_event_virt(unsigned long evt, @@ -667,10 +566,10 @@ static __always_inline irqreturn_t timer_handler(cons= t int access, { unsigned long ctrl; =20 - ctrl =3D arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt); + ctrl =3D arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { ctrl |=3D ARCH_TIMER_CTRL_IT_MASK; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); evt->event_handler(evt); return IRQ_HANDLED; } @@ -692,28 +591,14 @@ static irqreturn_t arch_timer_handler_phys(int irq, v= oid *dev_id) return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); } =20 -static irqreturn_t arch_timer_handler_phys_mem(int irq, void *dev_id) -{ - struct clock_event_device *evt =3D dev_id; - - return timer_handler(ARCH_TIMER_MEM_PHYS_ACCESS, evt); -} - -static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) -{ - struct clock_event_device *evt =3D dev_id; - - return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); -} - static __always_inline int arch_timer_shutdown(const int access, struct clock_event_device *clk) { unsigned long ctrl; =20 - ctrl =3D arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl =3D arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl &=3D ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); =20 return 0; } @@ -728,23 +613,13 @@ static int arch_timer_shutdown_phys(struct clock_even= t_device *clk) return arch_timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); } =20 -static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) -{ - return arch_timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); -} - -static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) -{ - return arch_timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); -} - static __always_inline void set_next_event(const int access, unsigned long= evt, struct clock_event_device *clk) { unsigned long ctrl; u64 cnt; =20 - ctrl =3D arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl =3D arch_timer_reg_read_cp15(access, ARCH_TIMER_REG_CTRL); ctrl |=3D ARCH_TIMER_CTRL_ENABLE; ctrl &=3D ~ARCH_TIMER_CTRL_IT_MASK; =20 @@ -753,8 +628,8 @@ static __always_inline void set_next_event(const int ac= cess, unsigned long evt, else cnt =3D __arch_counter_get_cntvct(); =20 - arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CVAL, evt + cnt); + arch_timer_reg_write_cp15(access, ARCH_TIMER_REG_CTRL, ctrl); } =20 static int arch_timer_set_next_event_virt(unsigned long evt, @@ -771,60 +646,6 @@ static int arch_timer_set_next_event_phys(unsigned lon= g evt, return 0; } =20 -static noinstr u64 arch_counter_get_cnt_mem(struct arch_timer *t, int offs= et_lo) -{ - u32 cnt_lo, cnt_hi, tmp_hi; - - do { - cnt_hi =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= + 4)); - cnt_lo =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= )); - tmp_hi =3D __le32_to_cpu((__le32 __force)__raw_readl(t->base + offset_lo= + 4)); - } while (cnt_hi !=3D tmp_hi); - - return ((u64) cnt_hi << 32) | cnt_lo; -} - -static __always_inline void set_next_event_mem(const int access, unsigned = long evt, - struct clock_event_device *clk) -{ - struct arch_timer *timer =3D to_arch_timer(clk); - unsigned long ctrl; - u64 cnt; - - ctrl =3D arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); - - /* Timer must be disabled before programming CVAL */ - if (ctrl & ARCH_TIMER_CTRL_ENABLE) { - ctrl &=3D ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); - } - - ctrl |=3D ARCH_TIMER_CTRL_ENABLE; - ctrl &=3D ~ARCH_TIMER_CTRL_IT_MASK; - - if (access =3D=3D ARCH_TIMER_MEM_VIRT_ACCESS) - cnt =3D arch_counter_get_cnt_mem(timer, CNTVCT_LO); - else - cnt =3D arch_counter_get_cnt_mem(timer, CNTPCT_LO); - - arch_timer_reg_write(access, ARCH_TIMER_REG_CVAL, evt + cnt, clk); - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); -} - -static int arch_timer_set_next_event_virt_mem(unsigned long evt, - struct clock_event_device *clk) -{ - set_next_event_mem(ARCH_TIMER_MEM_VIRT_ACCESS, evt, clk); - return 0; -} - -static int arch_timer_set_next_event_phys_mem(unsigned long evt, - struct clock_event_device *clk) -{ - set_next_event_mem(ARCH_TIMER_MEM_PHYS_ACCESS, evt, clk); - return 0; -} - static u64 __arch_timer_check_delta(void) { #ifdef CONFIG_ARM64 @@ -850,63 +671,41 @@ static u64 __arch_timer_check_delta(void) return CLOCKSOURCE_MASK(arch_counter_get_width()); } =20 -static void __arch_timer_setup(unsigned type, - struct clock_event_device *clk) +static void __arch_timer_setup(struct clock_event_device *clk) { + typeof(clk->set_next_event) sne; u64 max_delta; =20 clk->features =3D CLOCK_EVT_FEAT_ONESHOT; =20 - if (type =3D=3D ARCH_TIMER_TYPE_CP15) { - typeof(clk->set_next_event) sne; - - arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); - - if (arch_timer_c3stop) - clk->features |=3D CLOCK_EVT_FEAT_C3STOP; - clk->name =3D "arch_sys_timer"; - clk->rating =3D 450; - clk->cpumask =3D cpumask_of(smp_processor_id()); - clk->irq =3D arch_timer_ppi[arch_timer_uses_ppi]; - switch (arch_timer_uses_ppi) { - case ARCH_TIMER_VIRT_PPI: - clk->set_state_shutdown =3D arch_timer_shutdown_virt; - clk->set_state_oneshot_stopped =3D arch_timer_shutdown_virt; - sne =3D erratum_handler(set_next_event_virt); - break; - case ARCH_TIMER_PHYS_SECURE_PPI: - case ARCH_TIMER_PHYS_NONSECURE_PPI: - case ARCH_TIMER_HYP_PPI: - clk->set_state_shutdown =3D arch_timer_shutdown_phys; - clk->set_state_oneshot_stopped =3D arch_timer_shutdown_phys; - sne =3D erratum_handler(set_next_event_phys); - break; - default: - BUG(); - } + arch_timer_check_ool_workaround(ate_match_local_cap_id, NULL); =20 - clk->set_next_event =3D sne; - max_delta =3D __arch_timer_check_delta(); - } else { - clk->features |=3D CLOCK_EVT_FEAT_DYNIRQ; - clk->name =3D "arch_mem_timer"; - clk->rating =3D 400; - clk->cpumask =3D cpu_possible_mask; - if (arch_timer_mem_use_virtual) { - clk->set_state_shutdown =3D arch_timer_shutdown_virt_mem; - clk->set_state_oneshot_stopped =3D arch_timer_shutdown_virt_mem; - clk->set_next_event =3D - arch_timer_set_next_event_virt_mem; - } else { - clk->set_state_shutdown =3D arch_timer_shutdown_phys_mem; - clk->set_state_oneshot_stopped =3D arch_timer_shutdown_phys_mem; - clk->set_next_event =3D - arch_timer_set_next_event_phys_mem; - } - - max_delta =3D CLOCKSOURCE_MASK(56); + if (arch_timer_c3stop) + clk->features |=3D CLOCK_EVT_FEAT_C3STOP; + clk->name =3D "arch_sys_timer"; + clk->rating =3D 450; + clk->cpumask =3D cpumask_of(smp_processor_id()); + clk->irq =3D arch_timer_ppi[arch_timer_uses_ppi]; + switch (arch_timer_uses_ppi) { + case ARCH_TIMER_VIRT_PPI: + clk->set_state_shutdown =3D arch_timer_shutdown_virt; + clk->set_state_oneshot_stopped =3D arch_timer_shutdown_virt; + sne =3D erratum_handler(set_next_event_virt); + break; + case ARCH_TIMER_PHYS_SECURE_PPI: + case ARCH_TIMER_PHYS_NONSECURE_PPI: + case ARCH_TIMER_HYP_PPI: + clk->set_state_shutdown =3D arch_timer_shutdown_phys; + clk->set_state_oneshot_stopped =3D arch_timer_shutdown_phys; + sne =3D erratum_handler(set_next_event_phys); + break; + default: + BUG(); } =20 + clk->set_next_event =3D sne; + max_delta =3D __arch_timer_check_delta(); + clk->set_state_shutdown(clk); =20 clockevents_config_and_register(clk, arch_timer_rate, 0xf, max_delta); @@ -1029,7 +828,7 @@ static int arch_timer_starting_cpu(unsigned int cpu) struct clock_event_device *clk =3D this_cpu_ptr(arch_timer_evt); u32 flags; =20 - __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk); + __arch_timer_setup(clk); =20 flags =3D check_ppi_trigger(arch_timer_ppi[arch_timer_uses_ppi]); enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], flags); @@ -1075,22 +874,12 @@ static void __init arch_timer_of_configure_rate(u32 = rate, struct device_node *np pr_warn("frequency not available\n"); } =20 -static void __init arch_timer_banner(unsigned type) +static void __init arch_timer_banner(void) { - pr_info("%s%s%s timer(s) running at %lu.%02luMHz (%s%s%s).\n", - type & ARCH_TIMER_TYPE_CP15 ? "cp15" : "", - type =3D=3D (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? - " and " : "", - type & ARCH_TIMER_TYPE_MEM ? "mmio" : "", + pr_info("cp15 timer running at %lu.%02luMHz (%s).\n", (unsigned long)arch_timer_rate / 1000000, (unsigned long)(arch_timer_rate / 10000) % 100, - type & ARCH_TIMER_TYPE_CP15 ? - (arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) ? "virt" : "phys" : - "", - type =3D=3D (ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM) ? "/" : "", - type & ARCH_TIMER_TYPE_MEM ? - arch_timer_mem_use_virtual ? "virt" : "phys" : - ""); + (arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) ? "virt" : "phys"); } =20 u32 arch_timer_get_rate(void) @@ -1108,11 +897,6 @@ bool arch_timer_evtstrm_available(void) return cpumask_test_cpu(raw_smp_processor_id(), &evtstrm_available); } =20 -static noinstr u64 arch_counter_get_cntvct_mem(void) -{ - return arch_counter_get_cnt_mem(arch_timer_mem, CNTVCT_LO); -} - static struct arch_timer_kvm_info arch_timer_kvm_info; =20 struct arch_timer_kvm_info *arch_timer_get_kvm_info(void) @@ -1120,42 +904,35 @@ struct arch_timer_kvm_info *arch_timer_get_kvm_info(= void) return &arch_timer_kvm_info; } =20 -static void __init arch_counter_register(unsigned type) +static void __init arch_counter_register(void) { u64 (*scr)(void); + u64 (*rd)(void); u64 start_count; int width; =20 - /* Register the CP15 based counter if we have one */ - if (type & ARCH_TIMER_TYPE_CP15) { - u64 (*rd)(void); - - if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || - arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) { - if (arch_timer_counter_has_wa()) { - rd =3D arch_counter_get_cntvct_stable; - scr =3D raw_counter_get_cntvct_stable; - } else { - rd =3D arch_counter_get_cntvct; - scr =3D arch_counter_get_cntvct; - } + if ((IS_ENABLED(CONFIG_ARM64) && !is_hyp_mode_available()) || + arch_timer_uses_ppi =3D=3D ARCH_TIMER_VIRT_PPI) { + if (arch_timer_counter_has_wa()) { + rd =3D arch_counter_get_cntvct_stable; + scr =3D raw_counter_get_cntvct_stable; } else { - if (arch_timer_counter_has_wa()) { - rd =3D arch_counter_get_cntpct_stable; - scr =3D raw_counter_get_cntpct_stable; - } else { - rd =3D arch_counter_get_cntpct; - scr =3D arch_counter_get_cntpct; - } + rd =3D arch_counter_get_cntvct; + scr =3D arch_counter_get_cntvct; } - - arch_timer_read_counter =3D rd; - clocksource_counter.vdso_clock_mode =3D vdso_default; } else { - arch_timer_read_counter =3D arch_counter_get_cntvct_mem; - scr =3D arch_counter_get_cntvct_mem; + if (arch_timer_counter_has_wa()) { + rd =3D arch_counter_get_cntpct_stable; + scr =3D raw_counter_get_cntpct_stable; + } else { + rd =3D arch_counter_get_cntpct; + scr =3D arch_counter_get_cntpct; + } } =20 + arch_timer_read_counter =3D rd; + clocksource_counter.vdso_clock_mode =3D vdso_default; + width =3D arch_counter_get_width(); clocksource_counter.mask =3D CLOCKSOURCE_MASK(width); cyclecounter.mask =3D CLOCKSOURCE_MASK(width); @@ -1303,76 +1080,10 @@ static int __init arch_timer_register(void) return err; } =20 -static int __init arch_timer_mem_register(void __iomem *base, unsigned int= irq) -{ - int ret; - irq_handler_t func; - - arch_timer_mem =3D kzalloc(sizeof(*arch_timer_mem), GFP_KERNEL); - if (!arch_timer_mem) - return -ENOMEM; - - arch_timer_mem->base =3D base; - arch_timer_mem->evt.irq =3D irq; - __arch_timer_setup(ARCH_TIMER_TYPE_MEM, &arch_timer_mem->evt); - - if (arch_timer_mem_use_virtual) - func =3D arch_timer_handler_virt_mem; - else - func =3D arch_timer_handler_phys_mem; - - ret =3D request_irq(irq, func, IRQF_TIMER, "arch_mem_timer", &arch_timer_= mem->evt); - if (ret) { - pr_err("Failed to request mem timer irq\n"); - kfree(arch_timer_mem); - arch_timer_mem =3D NULL; - } - - return ret; -} - -static const struct of_device_id arch_timer_of_match[] __initconst =3D { - { .compatible =3D "arm,armv7-timer", }, - { .compatible =3D "arm,armv8-timer", }, - {}, -}; - -static const struct of_device_id arch_timer_mem_of_match[] __initconst =3D= { - { .compatible =3D "arm,armv7-timer-mem", }, - {}, -}; - -static bool __init arch_timer_needs_of_probing(void) -{ - struct device_node *dn; - bool needs_probing =3D false; - unsigned int mask =3D ARCH_TIMER_TYPE_CP15 | ARCH_TIMER_TYPE_MEM; - - /* We have two timers, and both device-tree nodes are probed. */ - if ((arch_timers_present & mask) =3D=3D mask) - return false; - - /* - * Only one type of timer is probed, - * check if we have another type of timer node in device-tree. - */ - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) - dn =3D of_find_matching_node(NULL, arch_timer_mem_of_match); - else - dn =3D of_find_matching_node(NULL, arch_timer_of_match); - - if (dn && of_device_is_available(dn)) - needs_probing =3D true; - - of_node_put(dn); - - return needs_probing; -} - static int __init arch_timer_common_init(void) { - arch_timer_banner(arch_timers_present); - arch_counter_register(arch_timers_present); + arch_timer_banner(); + arch_counter_register(); return arch_timer_arch_init(); } =20 @@ -1421,13 +1132,11 @@ static int __init arch_timer_of_init(struct device_= node *np) u32 rate; bool has_names; =20 - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { + if (arch_timer_evt) { pr_warn("multiple nodes in dt, skipping\n"); return 0; } =20 - arch_timers_present |=3D ARCH_TIMER_TYPE_CP15; - has_names =3D of_property_present(np, "interrupt-names"); =20 for (i =3D ARCH_TIMER_PHYS_SECURE_PPI; i < ARCH_TIMER_MAX_TIMER_PPI; i++)= { @@ -1472,283 +1181,22 @@ static int __init arch_timer_of_init(struct device= _node *np) if (ret) return ret; =20 - if (arch_timer_needs_of_probing()) - return 0; - return arch_timer_common_init(); } TIMER_OF_DECLARE(armv7_arch_timer, "arm,armv7-timer", arch_timer_of_init); TIMER_OF_DECLARE(armv8_arch_timer, "arm,armv8-timer", arch_timer_of_init); =20 -static u32 __init -arch_timer_mem_frame_get_cntfrq(struct arch_timer_mem_frame *frame) -{ - void __iomem *base; - u32 rate; - - base =3D ioremap(frame->cntbase, frame->size); - if (!base) { - pr_err("Unable to map frame @ %pa\n", &frame->cntbase); - return 0; - } - - rate =3D readl_relaxed(base + CNTFRQ); - - iounmap(base); - - return rate; -} - -static struct arch_timer_mem_frame * __init -arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem) -{ - struct arch_timer_mem_frame *frame, *best_frame =3D NULL; - void __iomem *cntctlbase; - u32 cnttidr; - int i; - - cntctlbase =3D ioremap(timer_mem->cntctlbase, timer_mem->size); - if (!cntctlbase) { - pr_err("Can't map CNTCTLBase @ %pa\n", - &timer_mem->cntctlbase); - return NULL; - } - - cnttidr =3D readl_relaxed(cntctlbase + CNTTIDR); - - /* - * Try to find a virtual capable frame. Otherwise fall back to a - * physical capable frame. - */ - for (i =3D 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { - u32 cntacr =3D CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | - CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; - - frame =3D &timer_mem->frame[i]; - if (!frame->valid) - continue; - - /* Try enabling everything, and see what sticks */ - writel_relaxed(cntacr, cntctlbase + CNTACR(i)); - cntacr =3D readl_relaxed(cntctlbase + CNTACR(i)); - - if ((cnttidr & CNTTIDR_VIRT(i)) && - !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) { - best_frame =3D frame; - arch_timer_mem_use_virtual =3D true; - break; - } - - if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) - continue; - - best_frame =3D frame; - } - - iounmap(cntctlbase); - - return best_frame; -} - -static int __init -arch_timer_mem_frame_register(struct arch_timer_mem_frame *frame) -{ - void __iomem *base; - int ret, irq; - - if (arch_timer_mem_use_virtual) - irq =3D frame->virt_irq; - else - irq =3D frame->phys_irq; - - if (!irq) { - pr_err("Frame missing %s irq.\n", - arch_timer_mem_use_virtual ? "virt" : "phys"); - return -EINVAL; - } - - if (!request_mem_region(frame->cntbase, frame->size, - "arch_mem_timer")) - return -EBUSY; - - base =3D ioremap(frame->cntbase, frame->size); - if (!base) { - pr_err("Can't map frame's registers\n"); - return -ENXIO; - } - - ret =3D arch_timer_mem_register(base, irq); - if (ret) { - iounmap(base); - return ret; - } - - arch_timers_present |=3D ARCH_TIMER_TYPE_MEM; - - return 0; -} - -static int __init arch_timer_mem_of_init(struct device_node *np) -{ - struct arch_timer_mem *timer_mem; - struct arch_timer_mem_frame *frame; - struct resource res; - int ret =3D -EINVAL; - u32 rate; - - timer_mem =3D kzalloc(sizeof(*timer_mem), GFP_KERNEL); - if (!timer_mem) - return -ENOMEM; - - if (of_address_to_resource(np, 0, &res)) - goto out; - timer_mem->cntctlbase =3D res.start; - timer_mem->size =3D resource_size(&res); - - for_each_available_child_of_node_scoped(np, frame_node) { - u32 n; - struct arch_timer_mem_frame *frame; - - if (of_property_read_u32(frame_node, "frame-number", &n)) { - pr_err(FW_BUG "Missing frame-number.\n"); - goto out; - } - if (n >=3D ARCH_TIMER_MEM_MAX_FRAMES) { - pr_err(FW_BUG "Wrong frame-number, only 0-%u are permitted.\n", - ARCH_TIMER_MEM_MAX_FRAMES - 1); - goto out; - } - frame =3D &timer_mem->frame[n]; - - if (frame->valid) { - pr_err(FW_BUG "Duplicated frame-number.\n"); - goto out; - } - - if (of_address_to_resource(frame_node, 0, &res)) - goto out; - - frame->cntbase =3D res.start; - frame->size =3D resource_size(&res); - - frame->virt_irq =3D irq_of_parse_and_map(frame_node, - ARCH_TIMER_VIRT_SPI); - frame->phys_irq =3D irq_of_parse_and_map(frame_node, - ARCH_TIMER_PHYS_SPI); - - frame->valid =3D true; - } - - frame =3D arch_timer_mem_find_best_frame(timer_mem); - if (!frame) { - pr_err("Unable to find a suitable frame in timer @ %pa\n", - &timer_mem->cntctlbase); - ret =3D -EINVAL; - goto out; - } - - rate =3D arch_timer_mem_frame_get_cntfrq(frame); - arch_timer_of_configure_rate(rate, np); - - ret =3D arch_timer_mem_frame_register(frame); - if (!ret && !arch_timer_needs_of_probing()) - ret =3D arch_timer_common_init(); -out: - kfree(timer_mem); - return ret; -} -TIMER_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", - arch_timer_mem_of_init); - #ifdef CONFIG_ACPI_GTDT -static int __init -arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem) -{ - struct arch_timer_mem_frame *frame; - u32 rate; - int i; - - for (i =3D 0; i < ARCH_TIMER_MEM_MAX_FRAMES; i++) { - frame =3D &timer_mem->frame[i]; - - if (!frame->valid) - continue; - - rate =3D arch_timer_mem_frame_get_cntfrq(frame); - if (rate =3D=3D arch_timer_rate) - continue; - - pr_err(FW_BUG "CNTFRQ mismatch: frame @ %pa: (0x%08lx), CPU: (0x%08lx)\n= ", - &frame->cntbase, - (unsigned long)rate, (unsigned long)arch_timer_rate); - - return -EINVAL; - } - - return 0; -} - -static int __init arch_timer_mem_acpi_init(int platform_timer_count) -{ - struct arch_timer_mem *timers, *timer; - struct arch_timer_mem_frame *frame, *best_frame =3D NULL; - int timer_count, i, ret =3D 0; - - timers =3D kcalloc(platform_timer_count, sizeof(*timers), - GFP_KERNEL); - if (!timers) - return -ENOMEM; - - ret =3D acpi_arch_timer_mem_init(timers, &timer_count); - if (ret || !timer_count) - goto out; - - /* - * While unlikely, it's theoretically possible that none of the frames - * in a timer expose the combination of feature we want. - */ - for (i =3D 0; i < timer_count; i++) { - timer =3D &timers[i]; - - frame =3D arch_timer_mem_find_best_frame(timer); - if (!best_frame) - best_frame =3D frame; - - ret =3D arch_timer_mem_verify_cntfrq(timer); - if (ret) { - pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n"); - goto out; - } - - if (!best_frame) /* implies !frame */ - /* - * Only complain about missing suitable frames if we - * haven't already found one in a previous iteration. - */ - pr_err("Unable to find a suitable frame in timer @ %pa\n", - &timer->cntctlbase); - } - - if (best_frame) - ret =3D arch_timer_mem_frame_register(best_frame); -out: - kfree(timers); - return ret; -} - -/* Initialize per-processor generic timer and memory-mapped timer(if prese= nt) */ static int __init arch_timer_acpi_init(struct acpi_table_header *table) { - int ret, platform_timer_count; + int ret; =20 - if (arch_timers_present & ARCH_TIMER_TYPE_CP15) { + if (arch_timer_evt) { pr_warn("already initialized, skipping\n"); return -EINVAL; } =20 - arch_timers_present |=3D ARCH_TIMER_TYPE_CP15; - - ret =3D acpi_gtdt_init(table, &platform_timer_count); + ret =3D acpi_gtdt_init(table, NULL); if (ret) return ret; =20 @@ -1790,10 +1238,6 @@ static int __init arch_timer_acpi_init(struct acpi_t= able_header *table) if (ret) return ret; =20 - if (platform_timer_count && - arch_timer_mem_acpi_init(platform_timer_count)) - pr_err("Failed to initialize memory-mapped timer.\n"); - return arch_timer_common_init(); } TIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init); diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm= _arch_timer.h index ce6521ad04d12..2eda895f19f54 100644 --- a/include/clocksource/arm_arch_timer.h +++ b/include/clocksource/arm_arch_timer.h @@ -9,9 +9,6 @@ #include #include =20 -#define ARCH_TIMER_TYPE_CP15 BIT(0) -#define ARCH_TIMER_TYPE_MEM BIT(1) - #define ARCH_TIMER_CTRL_ENABLE (1 << 0) #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) #define ARCH_TIMER_CTRL_IT_STAT (1 << 2) @@ -51,8 +48,6 @@ enum arch_timer_spi_nr { =20 #define ARCH_TIMER_PHYS_ACCESS 0 #define ARCH_TIMER_VIRT_ACCESS 1 -#define ARCH_TIMER_MEM_PHYS_ACCESS 2 -#define ARCH_TIMER_MEM_VIRT_ACCESS 3 =20 #define ARCH_TIMER_MEM_MAX_FRAMES 8 =20 --=20 2.39.2 From nobody Sat Oct 4 15:57:19 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D19523AE9B; Thu, 14 Aug 2025 15:46:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186389; cv=none; b=GzXAWhcMVaT01wpnbnVLHakCcWRJpT+181MDuAg+XsEDsPqoPOQAobOtfqDZ1dRAR2d1P1fbVLceoiVZDr4R2hjHbXj8NwX4uM6ygneoIR++f6x/xkDb+CTCamTz4KqYkoIdUyv9txqfojYJuZbs0RWUk0ULbB3FLUc+5KuYFGQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755186389; c=relaxed/simple; bh=iSjzjmWTu80cwcbL4cT/to0KlVsFsM7JJGnphItTq5s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=NUXGe3bC2M5jfYsRISjsNKg9eUlnNMirO0c0UDzQn8BUZvPSFAIWluOnMOByxstH8LnsIUyNJyztgFEfwCZhu1jYAm61HY5UrFk5x35LpdP9NJV59djVjgO6otlH6NqZ2YgCudmUBLYSzhED00nKfQEqWpV2hhiYkXBHVowCdyY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fF7wYjhZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fF7wYjhZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DC754C4CEEF; Thu, 14 Aug 2025 15:46:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1755186388; bh=iSjzjmWTu80cwcbL4cT/to0KlVsFsM7JJGnphItTq5s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fF7wYjhZFUqs3vr7YwAWauWU54banRqHRl2x4hrTX4DI+Lud6nrQu1ZY4dXh7sI8f b4VbGwLI/89AghcGVtl+bD53+vwY3/9SVfcBv0ghRl3/8+Lun/5RM2Wcv1NuBFfT82 i/ePzioR8hvE+zj2bODZDNxeAu1vVs6NOj6k/xUsMubVquDHmQ819m+aZdzfHBOddB iOFDz/U2uNE56pnrAu8RkAaa1ixZbWrxK/LKgCHZIfPoIGsaAwIY6E0oWDbVYidsoo RdfRP2ENVzwWjO1jijYkXurAVX+7HnZg3XupfxyrAznJ761iLb8gN5PNQUoi3M4Qq6 v7/tOpG3VQbNg== Received: from sofa.misterjones.org ([185.219.108.64] helo=valley-girl.lan) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1uma9q-007VqB-Qc; Thu, 14 Aug 2025 16:46:26 +0100 From: Marc Zyngier To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: Lorenzo Pieralisi , Hanjun Guo , Sudeep Holla , "Rafael J. Wysocki" , Daniel Lezcano , Thomas Gleixner , Mark Rutland , Alexandru Elisei , Steven Price Subject: [PATCH v2 4/4] clocksource/drivers/arm_arch_timer_mmio: Add MMIO clocksource Date: Thu, 14 Aug 2025 16:46:22 +0100 Message-Id: <20250814154622.10193-5-maz@kernel.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20250814154622.10193-1-maz@kernel.org> References: <20250814154622.10193-1-maz@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org, lpieralisi@kernel.org, guohanjun@huawei.com, sudeep.holla@arm.com, rafael@kernel.org, daniel.lezcano@linaro.org, tglx@linutronix.de, mark.rutland@arm.com, alexandru.elisei@arm.com, steven.price@arm.com X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false Content-Type: text/plain; charset="utf-8" The MMIO driver can also double as a clocksource, something that was missing in its previous incarnation. Add it for completeness. Tested-by: Sudeep Holla Reviewed-by: Sudeep Holla Link: https://lore.kernel.org/r/20250807160243.1970533-5-maz@kernel.org Signed-off-by: Marc Zyngier --- drivers/clocksource/arm_arch_timer_mmio.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/clocksource/arm_arch_timer_mmio.c b/drivers/clocksourc= e/arm_arch_timer_mmio.c index 3522d1d8cb97b..ebe1987d651eb 100644 --- a/drivers/clocksource/arm_arch_timer_mmio.c +++ b/drivers/clocksource/arm_arch_timer_mmio.c @@ -45,6 +45,7 @@ enum arch_timer_access { =20 struct arch_timer { struct clock_event_device evt; + struct clocksource cs; struct arch_timer_mem *gt_block; void __iomem *base; enum arch_timer_access access; @@ -52,6 +53,7 @@ struct arch_timer { }; =20 #define evt_to_arch_timer(e) container_of(e, struct arch_timer, evt) +#define cs_to_arch_timer(c) container_of(c, struct arch_timer, cs) =20 static void arch_timer_mmio_write(struct arch_timer *timer, enum arch_timer_reg reg, u64 val) @@ -128,6 +130,13 @@ static noinstr u64 arch_counter_mmio_get_cnt(struct ar= ch_timer *t) return ((u64) cnt_hi << 32) | cnt_lo; } =20 +static u64 arch_mmio_counter_read(struct clocksource *cs) +{ + struct arch_timer *at =3D cs_to_arch_timer(cs); + + return arch_counter_mmio_get_cnt(at); +} + static int arch_timer_mmio_shutdown(struct clock_event_device *clk) { struct arch_timer *at =3D evt_to_arch_timer(clk); @@ -256,6 +265,16 @@ static void arch_timer_mmio_setup(struct arch_timer *a= t, int irq) (unsigned long)CLOCKSOURCE_MASK(56)); =20 enable_irq(at->evt.irq); + + at->cs =3D (struct clocksource) { + .name =3D "arch_mmio_counter", + .rating =3D 300, + .read =3D arch_mmio_counter_read, + .mask =3D CLOCKSOURCE_MASK(56), + .flags =3D CLOCK_SOURCE_IS_CONTINUOUS, + }; + + clocksource_register_hz(&at->cs, at->rate); } =20 static int arch_timer_mmio_frame_register(struct platform_device *pdev, --=20 2.39.2