mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: BAREBOX <barebox@lists.infradead.org>
Subject: [PATCH 23/27] clocksource: add a driver for the PXA OS timer and its watchdog
Date: Sun, 16 Aug 2026 19:56:43 +0200	[thread overview]
Message-ID: <20260816-pxa3xx-v1-23-f3c3d7a6c43f@pengutronix.de> (raw)
In-Reply-To: <20260816-pxa3xx-v1-0-f3c3d7a6c43f@pengutronix.de>

The PXA clocksource was registered from a core_initcall in mach-pxa which
is not suitable for multiarch. Move it over to a platform driver which probes
from device tree.

Match register 3 of the same timer doubles as a watchdog: arm it by writing
a match value ahead of the counter and setting OWER_WME, and the match
resets the machine. That is the same block the clocksource uses and there
is one device tree node for it, so register the watchdog from the same
driver rather than inventing a second node for the same registers.

OWER_WME cannot be cleared again - the watchdog runs until it resets the
machine - so refuse a timeout of zero once it is armed instead of
pretending to stop it. Verified on a PXA303: the board resets on schedule
whether or not something asked for it to be disabled in between.

The counter is 32 bit and the match has to fit in it, which puts the
maximum timeout at 1321s at this part's 3.25MHz.

Assisted-by: Claude Opus 5
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
 arch/arm/mach-pxa/Makefile      |   1 -
 arch/arm/mach-pxa/clocksource.c |  41 -----------
 drivers/clocksource/Kconfig     |   7 ++
 drivers/clocksource/Makefile    |   1 +
 drivers/clocksource/timer-pxa.c | 151 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 159 insertions(+), 42 deletions(-)

diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 86d9c4ca95..7a9ca83199 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -1,6 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-obj-y += clocksource.o
 obj-y += sleep.o
 obj-y += common.o
 obj-y += devices.o
diff --git a/arch/arm/mach-pxa/clocksource.c b/arch/arm/mach-pxa/clocksource.c
deleted file mode 100644
index 3bc95827d8..0000000000
--- a/arch/arm/mach-pxa/clocksource.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * (C) Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <common.h>
-#include <init.h>
-#include <clock.h>
-#include <asm/io.h>
-
-#define OSCR	0x40A00010
-
-static uint64_t pxa_clocksource_read(void)
-{
-	return readl(OSCR);
-}
-
-static struct clocksource cs = {
-	.read	= pxa_clocksource_read,
-	.mask	= 0xffffffff,
-	.shift	= 20,
-	.priority = 80,
-};
-
-static int clocksource_init(void)
-{
-	cs.mult = clocksource_hz2mult(3250000, cs.shift);
-
-	return init_clock(&cs);
-}
-
-core_initcall(clocksource_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5ee83d2b38..89e0be7894 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -120,6 +120,13 @@ config ARMV7M_SYSTICK
 	help
 	  This option enables support for the ARMv7M system timer unit.
 
+config CLOCKSOURCE_PXA
+	bool "Clocksource for PXA SoCs"
+	depends on OFDEVICE && (ARCH_PXA || COMPILE_TEST)
+	default ARCH_PXA
+	help
+	  This option enables support for the OS timer found on PXA SoCs.
+
 config CLKSRC_STM32
 	bool "Clocksource for STM32 SoCs"
 	depends on OFDEVICE && (ARCH_STM32 || COMPILE_TEST)
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index dff8255650..0f8a54d819 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_CLINT_TIMER) += timer-clint.o
 obj-$(CONFIG_RISCV_TIMER) += timer-riscv.o
 obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o
 obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
+obj-$(CONFIG_CLOCKSOURCE_PXA) += timer-pxa.o
diff --git a/drivers/clocksource/timer-pxa.c b/drivers/clocksource/timer-pxa.c
new file mode 100644
index 0000000000..8834bbec0c
--- /dev/null
+++ b/drivers/clocksource/timer-pxa.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Clocksource and watchdog for the PXA OS timer.
+ *
+ * The two are one block: match register 3 doubles as the watchdog, so both
+ * live in the same driver rather than fighting over the device tree node.
+ *
+ * (C) Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
+ */
+
+#include <common.h>
+#include <clock.h>
+#include <driver.h>
+#include <init.h>
+#include <io.h>
+#include <watchdog.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#define OSMR3		0x0c	/* match register 3, the watchdog match */
+#define OSCR		0x10	/* counter, free running and running out of reset */
+#define OSSR		0x14	/* status */
+#define OWER		0x18	/* watchdog enable */
+
+#define OSSR_M3		(1 << 3)	/* match status channel 3 */
+#define OWER_WME	(1 << 0)	/* watchdog match enable */
+
+struct pxa_timer {
+	void __iomem *base;
+	unsigned long rate;
+	struct watchdog wd;
+};
+
+static inline struct pxa_timer *to_pxa_timer(struct watchdog *wd)
+{
+	return container_of(wd, struct pxa_timer, wd);
+}
+
+static void __iomem *pxa_timer_base;
+
+static uint64_t pxa_clocksource_read(void)
+{
+	return readl(pxa_timer_base + OSCR);
+}
+
+static struct clocksource pxa_cs = {
+	.read     = pxa_clocksource_read,
+	.mask     = CLOCKSOURCE_MASK(32),
+	.shift    = 20,
+	.priority = 80,
+};
+
+static int pxa_wdt_set_timeout(struct watchdog *wd, unsigned timeout)
+{
+	struct pxa_timer *timer = to_pxa_timer(wd);
+
+	if (!timeout) {
+		/*
+		 * OWER_WME only ever reads back the way it was written once:
+		 * the watchdog cannot be stopped again short of the reset it
+		 * is about to cause. Refuse rather than pretend.
+		 */
+		if (wd->running == WDOG_HW_RUNNING)
+			return -ENOSYS;
+
+		return 0;
+	}
+
+	writel(readl(timer->base + OSCR) + (u64)timeout * timer->rate,
+	       timer->base + OSMR3);
+	writel(OSSR_M3, timer->base + OSSR);
+	writel(OWER_WME, timer->base + OWER);
+
+	wd->running = WDOG_HW_RUNNING;
+
+	return 0;
+}
+
+static int pxa_timer_probe(struct device *dev)
+{
+	struct resource *iores;
+	struct pxa_timer *timer;
+	struct clk *clk;
+	int ret;
+
+	iores = dev_request_mem_resource(dev, 0);
+	if (IS_ERR(iores))
+		return PTR_ERR(iores);
+
+	clk = clk_get(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "cannot get clock\n");
+
+	ret = clk_enable(clk);
+	if (ret)
+		return dev_err_probe(dev, ret, "cannot enable clock\n");
+
+	timer = xzalloc(sizeof(*timer));
+	timer->base = IOMEM(iores->start);
+	timer->rate = clk_get_rate(clk);
+	if (!timer->rate)
+		return dev_err_probe(dev, -EINVAL, "clock has no rate\n");
+
+	pxa_timer_base = timer->base;
+	pxa_cs.mult = clocksource_hz2mult(timer->rate, pxa_cs.shift);
+
+	ret = init_clock(&pxa_cs);
+	if (ret)
+		return ret;
+
+	timer->wd.set_timeout = pxa_wdt_set_timeout;
+	timer->wd.hwdev = dev;
+	timer->wd.name = "pxa-wdt";
+	/* the counter is 32 bit, so that is as far ahead as a match reaches */
+	timer->wd.timeout_max = U32_MAX / timer->rate;
+	timer->wd.running = readl(timer->base + OWER) & OWER_WME ?
+			WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+
+	ret = watchdog_register(&timer->wd);
+	if (ret)
+		dev_warn(dev, "failed to register watchdog: %pe\n",
+			 ERR_PTR(ret));
+
+	return 0;
+}
+
+static const struct of_device_id pxa_timer_dt_ids[] = {
+	{ .compatible = "marvell,pxa-timer" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pxa_timer_dt_ids);
+
+static struct driver pxa_timer_driver = {
+	.name = "pxa-timer",
+	.probe = pxa_timer_probe,
+	.of_compatible = pxa_timer_dt_ids,
+};
+postcore_platform_driver(pxa_timer_driver);
+
+/*
+ * Under deep probe nothing refers to the timer by phandle, so it is not probed
+ * until the device tree walk reaches it - and that walk is in device tree
+ * order, which on PXA3xx puts the NAND controller a long way ahead of the
+ * timer. Everything in between would run its timeouts against the dummy
+ * clocksource.
+ */
+static int pxa_timer_of_init(void)
+{
+	return of_devices_ensure_probed_by_dev_id(pxa_timer_dt_ids);
+}
+coredevice_initcall(pxa_timer_of_init);

-- 
2.47.3




  parent reply	other threads:[~2026-08-16 18:02 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-16 17:56 [PATCH 00/27] ARM: Add pxa3xx and Raumfeld Speaker support Sascha Hauer
2026-08-16 17:56 ` [PATCH 01/27] ARM: pxa: remove PXA25x and PXA27x support Sascha Hauer
2026-08-16 17:56 ` [PATCH 02/27] video: remove the PXA framebuffer driver Sascha Hauer
2026-08-16 17:56 ` [PATCH 03/27] ARM: cache: drive the XSC3 cache with the ARMv4 functions Sascha Hauer
2026-08-16 17:56 ` [PATCH 04/27] mci: pxamci: get the clock from the clk API Sascha Hauer
2026-08-16 17:56 ` [PATCH 05/27] pwm: pxa: " Sascha Hauer
2026-08-16 17:56 ` [PATCH 06/27] serial: " Sascha Hauer
2026-08-16 17:56 ` [PATCH 07/27] clk: pxa: add a device tree clock driver for PXA3xx Sascha Hauer
2026-08-16 17:56 ` [PATCH 08/27] mtd: nand: nand_mrvl_nfc: honour marvell,nand-keep-config Sascha Hauer
2026-08-16 17:56 ` [PATCH 09/27] mtd: nand: nand_mrvl_nfc: support the nand-controller bindings Sascha Hauer
2026-08-16 17:56 ` [PATCH 10/27] mtd: nand: mrvl_nfc: keep the ready latch across a STATUS command Sascha Hauer
2026-08-16 17:56 ` [PATCH 11/27] mtd: nand: mrvl_nfc: do not report a command timeout as an error Sascha Hauer
2026-08-16 17:56 ` [PATCH 12/27] mci: pxamci: probe from the device tree Sascha Hauer
2026-08-16 17:56 ` [PATCH 13/27] serial: pxa: add device tree support Sascha Hauer
2026-08-16 17:56 ` [PATCH 14/27] serial: pxa: provide the Linux console name Sascha Hauer
2026-08-16 17:56 ` [PATCH 15/27] gpio: pxa: add a driver and switch the architecture to GPIOLIB Sascha Hauer
2026-08-16 17:56 ` [PATCH 16/27] ARM: pxa: add DEBUG_LL support Sascha Hauer
2026-08-16 17:56 ` [PATCH 17/27] ARM: pxa: let the board select the SoC Sascha Hauer
2026-08-16 17:56 ` [PATCH 18/27] ARM: pxa: enable device tree support Sascha Hauer
2026-08-16 17:56 ` [PATCH 19/27] scripts: add pxa-image Sascha Hauer
2026-08-16 17:56 ` [PATCH 20/27] ARM: pxa: add a NAND first stage loader Sascha Hauer
2026-08-16 17:56 ` [PATCH 21/27] filetype: detect PXA3xx NTIM images Sascha Hauer
2026-08-16 17:56 ` [PATCH 22/27] ARM: pxa: add a barebox update handler for NAND Sascha Hauer
2026-08-16 17:56 ` Sascha Hauer [this message]
2026-08-16 17:56 ` [PATCH 24/27] ARM: pxa: move over to MULTIARCH Sascha Hauer
2026-08-16 17:56 ` [PATCH 25/27] ARM: pxa: reset straight away and without complaining Sascha Hauer
2026-08-16 17:56 ` [PATCH 26/27] ARM: pxa: add Raumfeld Speaker board support Sascha Hauer
2026-08-16 17:56 ` [PATCH 27/27] ARM: multi_v5_v6_defconfig: enable PXA support Sascha Hauer
2026-08-17  7:35 ` [PATCH 00/27] ARM: Add pxa3xx and Raumfeld Speaker support Ahmad Fatoum
2026-08-19  9:26 ` Sascha Hauer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260816-pxa3xx-v1-23-f3c3d7a6c43f@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox