linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] clocksource: Support ARM SSE(Subsystems for Embedded)
@ 2025-08-21 15:24 Jisheng Zhang
  2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
  2025-08-21 15:24 ` [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver Jisheng Zhang
  0 siblings, 2 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-21 15:24 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, devicetree

Here is the ARM SSE(Subsystems for Embedded) timer doc URL:
https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en

Although the IP is mostly seen on MCU SoC platforms, but nothing
prevent it from being integrated into linux capable SoC platforms.

The IP core may have a system counter to generate timestamp value,
a system timer to raise an interrupt when a period has elapsed, and
a System Watchdog to detect errant system behaviour then reset the
system if a period elapses without ping.

The differences between this IP and arm mmio arch timer include not
limit to:
1. The system can add the timer frames as many as it want, I.E no
up to 8 timer frames limitation at all.
2. The IP supports watchdog.
3. physical timer only.
4. The system counter can be exposed to so can be under the control of
   linux.

Patch1 adds the dt-binding doc for it.
Patch2 introduces a clocksource+watchdog driver for the IP.


Jisheng Zhang (2):
  dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver

 .../bindings/timer/arm,sse_timer.yaml         |  90 +++
 drivers/clocksource/Kconfig                   |   7 +
 drivers/clocksource/Makefile                  |   1 +
 drivers/clocksource/timer-sse.c               | 540 ++++++++++++++++++
 4 files changed, 638 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
 create mode 100644 drivers/clocksource/timer-sse.c

-- 
2.50.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  2025-08-21 15:24 [PATCH 0/2] clocksource: Support ARM SSE(Subsystems for Embedded) Jisheng Zhang
@ 2025-08-21 15:24 ` Jisheng Zhang
  2025-08-21 15:55   ` Jisheng Zhang
                     ` (2 more replies)
  2025-08-21 15:24 ` [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver Jisheng Zhang
  1 sibling, 3 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-21 15:24 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, devicetree

Add binding doc for the ARM SSE(Subsystems for Embedded) timer. Here
is the document URL:
https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en

Although the IP is mostly seen on MCU SoC platforms, but nothing
prevent it from being integrated into linux capable SoC platforms.

The IP core may have a system counter to generate timestamp value,
a system timer to raise an interrupt when a period has elapsed, and
a System Watchdog to detect errant system behaviour then reset the
system if a period elapses without ping.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 .../bindings/timer/arm,sse_timer.yaml         | 90 +++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml

diff --git a/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
new file mode 100644
index 000000000000..37a79f9052d0
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/arm,sse_timer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ARM SSE(Subsystems for Embedded) system timer
+
+maintainers:
+  - Jisheng Zhang <jszhang@kernel.org>
+
+description: |+
+  ARM SSE(Subsystems for Embedded) system timer core may have a system counter
+  to generate timestamp value, a system timer to raise an interrupt when a
+  period has elapsed, and a System Watchdog to detect errant system behaviour
+  then reset the system if a period elapses without ping.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - arm,sse-timer
+
+  reg:
+    maxItems: 1
+    description: The system counter control frame base
+
+  clocks:
+    maxItems: 1
+
+  '#address-cells':
+    enum: [1, 2]
+
+  '#size-cells':
+    const: 1
+
+  ranges: true
+
+patternProperties:
+  '^frame@[0-9a-f]+$':
+    type: object
+    additionalProperties: false
+    description: A timer node has some frame sub-nodes, each frame can be timer frame or watchdog frame. Each frame has the following properties.
+    properties:
+      interrupts:
+        minItems: 1
+        items:
+          - description: timer irq
+
+      reg:
+        minItems: 1
+        items:
+          - description: 1st view base address
+          - description: 2nd optional view base address if this is a watchdog frame
+
+    required:
+      - interrupts
+      - reg
+
+required:
+  - compatible
+  - reg
+  - '#address-cells'
+  - '#size-cells'
+
+additionalProperties: false
+
+examples:
+  - |
+    timer@f7f3e000 {
+      compatible = "arm,sse-timer";
+      #address-cells = <1>;
+      #size-cells = <1>;
+      ranges;
+      reg = <0xf7f3e000 0x2000>;
+      clocks = <&core_clk>;
+
+      frame@f7f20000 {
+        reg = <0xf7f20000 0x1000>;
+        interrupts = <0 26 0x8>;
+      };
+
+      frame@f7f30000 {
+        interrupts = <0 15 0x8>;
+        reg = <0xf7f32000 0x1000>,
+              <0xf7f33000 0x1000>;
+      };
+    };
+
+...
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver
  2025-08-21 15:24 [PATCH 0/2] clocksource: Support ARM SSE(Subsystems for Embedded) Jisheng Zhang
  2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
@ 2025-08-21 15:24 ` Jisheng Zhang
  2025-08-21 15:52   ` Jisheng Zhang
  2025-08-22  9:43   ` kernel test robot
  1 sibling, 2 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-21 15:24 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, devicetree

Here is the ARM SSE(Subsystems for Embedded) timer doc URL:
https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en

Although the IP is mostly seen on MCU SoC platforms, but nothing
prevent it from being integrated into linux capable SoC platforms.

The IP core may have a system counter to generate timestamp value,
a system timer to raise an interrupt when a period has elapsed, and
a System Watchdog to detect errant system behaviour then reset the
system if a period elapses without ping.

The differences between this IP and arm mmio arch timer include not
limit to:
1. The system can add the timer frames as many as it want, I.E no
up to 8 timer frames limitation at all.
2. The IP supports watchdog.
3. physical timer only.
4. The system counter can be exposed to so can be under the control of
   linux.

Introduce a clocksource+watchdog driver for the ARM SSE timer IP.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 drivers/clocksource/Kconfig     |   7 +
 drivers/clocksource/Makefile    |   1 +
 drivers/clocksource/timer-sse.c | 540 ++++++++++++++++++++++++++++++++
 3 files changed, 548 insertions(+)
 create mode 100644 drivers/clocksource/timer-sse.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 645f517a1ac2..bfcbd7a1a498 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -152,6 +152,13 @@ config REALTEK_OTTO_TIMER
 	  RT8391, RTL8392, RTL8393 and RTL8396 and chips of the RTL930x series
 	  such as RTL9301, RTL9302 or RTL9303.
 
+config SSE_TIMER
+	bool "ARM SSE(Subsystems for Embedded) system timer driver"
+	depends on COMMON_CLK
+	default n
+	help
+	  Enables support for the ARM SSE(Subsystems for Embedded) system timer driver.
+
 config SUN4I_TIMER
 	bool "Sun4i timer driver" if COMPILE_TEST
 	depends on HAS_IOMEM
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 205bf3b0a8f3..dd688807694d 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_BCM2835_TIMER)	+= bcm2835_timer.o
 obj-$(CONFIG_CLPS711X_TIMER)	+= clps711x-timer.o
 obj-$(CONFIG_MXS_TIMER)		+= mxs_timer.o
 obj-$(CONFIG_CLKSRC_PXA)	+= timer-pxa.o
+obj-$(CONFIG_SSE_TIMER)		+= timer-sse.o
 obj-$(CONFIG_SUN4I_TIMER)	+= timer-sun4i.o
 obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
 obj-$(CONFIG_MESON6_TIMER)	+= timer-meson6.o
diff --git a/drivers/clocksource/timer-sse.c b/drivers/clocksource/timer-sse.c
new file mode 100644
index 000000000000..cf7d0bf07c2e
--- /dev/null
+++ b/drivers/clocksource/timer-sse.c
@@ -0,0 +1,540 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Synaptics Incorporated
+ *
+ * Author: Jisheng Zhang <jszhang@kernel.org>
+ *
+ * Some code are borrow from
+ * linux/drivers/clocksource/arm_arch_timer.c
+ * Copyright (C) 2011 ARM Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/watchdog.h>
+
+#define CNTCR				0x00
+#define CNTCV				0x08
+
+#define CNTPCT				0x00
+#define CNTP_CVAL			0x20
+#define CNTP_CTL			0x2c
+#define  CNTP_CTL_ENABLE		BIT(0)
+#define  CNTP_CTL_IMASK			BIT(1)
+#define  CNTP_CTL_ISTATUS		BIT(2)
+#define CNTP_AIVAL_RELOAD		0x48
+#define CNTP_AIVAL_CTL			0x4c
+#define  CNTP_AIVAL_CTL_EN		BIT(0)
+#define  CNTP_AIVAL_CTL_CLR		BIT(1)
+#define CNTP_CFG			0x50
+#define  CNTP_CFG_AIVAL_MASK		GENMASK(3, 0)
+#define  CNTP_CFG_AIVAL_IMPL		1
+
+#define WCS				0x00
+#define  WCS_EN				BIT(0)
+#define  WCS_WS0			BIT(1)
+#define  WCS_WS1			BIT(2)
+#define WOR				0x08
+#define WCV				0x10
+
+#define WRR				0x00
+
+#define SSE_WDT_DEFAULT_SECONDS		30
+
+enum sse_timer_mode {
+	SSE_TIMER_NORMAL,
+	SSE_TIMER_AUTOINC,
+};
+
+struct sse_timer_frame {
+	void __iomem *base;
+	struct clocksource cs;
+	struct clock_event_device ce;
+	u32 ticks_per_jiffy;
+	int irq;
+	enum sse_timer_mode mode;
+};
+
+struct sse_wdt_frame {
+	struct watchdog_device wdd;
+	void __iomem *ctrl_base;
+	void __iomem *refr_base;
+	unsigned long freq;
+	int irq;
+};
+
+struct sse_timer {
+	void __iomem *cntctrl_base;
+	struct clk *clk;
+	struct sse_timer_frame *timers;
+	struct sse_wdt_frame *wdts;
+	int timer_num;
+	int wdt_num;
+};
+
+#define cs_to_sse_timer_frame(x) \
+	container_of(x, struct sse_timer_frame, cs)
+#define ce_to_sse_timer_frame(x) \
+	container_of(x, struct sse_timer_frame, ce)
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0444);
+MODULE_PARM_DESC(nowayout,
+		 "Watchdog cannot be stopped once started (default="
+		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static __always_inline u64 sse_get_cntpct(struct sse_timer_frame *f)
+{
+#ifndef CONFIG_64BIT
+	u32 cnt_lo, cnt_hi, tmp_hi;
+
+	do {
+		cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT + 4));
+		cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT));
+		tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT + 4));
+	} while (cnt_hi != tmp_hi);
+
+	return ((u64) cnt_hi << 32) | cnt_lo;
+#else
+	return readq_relaxed(f->base + CNTPCT);
+#endif
+
+}
+
+static int sse_ce_shutdown(struct clock_event_device *ce)
+{
+	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
+	u32 val;
+
+	val = readl_relaxed(f->base + CNTP_CTL);
+	val &= ~CNTP_CTL_ENABLE;
+	writel_relaxed(val, f->base + CNTP_CTL);
+	return 0;
+}
+
+static int sse_ce_set_oneshot(struct clock_event_device *ce)
+{
+	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
+	u32 val;
+
+	f->mode = SSE_TIMER_NORMAL;
+
+	val = readl_relaxed(f->base + CNTP_CTL);
+	if (val & CNTP_CTL_ENABLE) {
+		val &= ~CNTP_CTL_ENABLE;
+		writel_relaxed(val, f->base + CNTP_CTL);
+	}
+
+	writel_relaxed(0, f->base + CNTP_AIVAL_CTL);
+
+	return 0;
+}
+
+static int sse_ce_set_periodic(struct clock_event_device *ce)
+{
+	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
+	u32 val;
+
+	f->mode = SSE_TIMER_AUTOINC;
+
+	val = readl_relaxed(f->base + CNTP_CTL);
+	if (val & CNTP_CTL_ENABLE) {
+		val &= ~CNTP_CTL_ENABLE;
+		writel_relaxed(val, f->base + CNTP_CTL);
+	}
+
+	val |= CNTP_CTL_ENABLE;
+	val &= ~CNTP_CTL_IMASK;
+
+	writel_relaxed(f->ticks_per_jiffy, f->base + CNTP_AIVAL_RELOAD);
+	writel_relaxed(CNTP_AIVAL_CTL_EN, f->base + CNTP_AIVAL_CTL);
+	writel_relaxed(val, f->base + CNTP_CTL);
+
+	return 0;
+}
+
+static int sse_ce_next_event(unsigned long evt, struct clock_event_device *ce)
+{
+	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
+	u32 val;
+	u64 cnt;
+
+	val = readl_relaxed(f->base + CNTP_CTL);
+	if (val & CNTP_CTL_ENABLE) {
+		val &= ~CNTP_CTL_ENABLE;
+		writel_relaxed(val, f->base + CNTP_CTL);
+	}
+
+	val |= CNTP_CTL_ENABLE;
+	val &= ~CNTP_CTL_IMASK;
+
+	cnt = sse_get_cntpct(f);
+	writeq_relaxed(evt + cnt, f->base + CNTP_CVAL);
+	writel_relaxed(val, f->base + CNTP_CTL);
+
+	return 0;
+}
+
+static irqreturn_t sse_timer_interrupt(int irq, void *dev_id)
+{
+	struct sse_timer_frame *f = dev_id;
+	u32 val;
+
+	val = readl_relaxed(f->base + CNTP_CTL);
+	if (!(val & CNTP_CTL_ISTATUS))
+		return IRQ_NONE;
+
+	if (f->mode == SSE_TIMER_AUTOINC) {
+		val = readl_relaxed(f->base + CNTP_AIVAL_CTL);
+		val &= ~CNTP_AIVAL_CTL_CLR;
+		writel_relaxed(val, f->base + CNTP_AIVAL_CTL);
+	} else {
+		val |= CNTP_CTL_IMASK;
+		writel_relaxed(val, f->base + CNTP_CTL);
+	}
+	f->ce.event_handler(&f->ce);
+
+	return IRQ_HANDLED;
+}
+
+static int sse_setup_clockevent(struct device *dev, struct sse_timer_frame *f,
+				unsigned long rate)
+{
+	int ret;
+	u32 val = readl_relaxed(f->base + CNTP_CFG);
+
+	f->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
+
+	f->ce.name = "sse-timer";
+	f->ce.rating = 300;
+	f->ce.irq = f->irq;
+	f->ce.cpumask = cpu_possible_mask;
+	f->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
+	f->ce.set_state_shutdown = sse_ce_shutdown;
+	f->ce.set_next_event = sse_ce_next_event;
+	f->ce.set_state_oneshot_stopped = sse_ce_shutdown;
+	if (FIELD_GET(CNTP_CFG_AIVAL_MASK, val) == CNTP_CFG_AIVAL_IMPL) {
+		f->ce.set_state_periodic = sse_ce_set_periodic;
+		f->ce.set_state_oneshot = sse_ce_set_oneshot;
+	}
+
+	clockevents_config_and_register(&f->ce, rate, 0xf, ULONG_MAX);
+
+	ret = devm_request_irq(dev, f->irq, sse_timer_interrupt,
+			       IRQF_TIMER | IRQF_NOBALANCING,
+			       f->ce.name, f);
+	if (ret) {
+		dev_err(dev, "Unable to register interrupt\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static noinstr u64 cs_sse_get_cntpct(struct clocksource *cs)
+{
+	struct sse_timer_frame *f = cs_to_sse_timer_frame(cs);
+
+	return sse_get_cntpct(f);
+}
+
+static int sse_setup_clocksource(struct device *dev, struct sse_timer_frame *f,
+				 unsigned long rate)
+{
+	int ret;
+
+	f->cs.name = "sse-timer";
+	f->cs.rating = 300;
+	f->cs.read = cs_sse_get_cntpct;
+	f->cs.mask = CLOCKSOURCE_MASK(64);
+	f->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+	ret = clocksource_register_hz(&f->cs, rate);
+	if (ret) {
+		dev_err(dev, "Couldn't register clock source.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static irqreturn_t sse_wdt_interrupt(int irq, void *dev_id)
+{
+	struct sse_wdt_frame *f = dev_id;
+	u32 val;
+
+	val = readl_relaxed(f->ctrl_base + WCS);
+	if (val & WCS_WS0)
+		watchdog_notify_pretimeout(&f->wdd);
+
+	return IRQ_HANDLED;
+}
+
+static int sse_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
+{
+	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
+
+	wdd->timeout = timeout;
+
+	/* Pretimeout is 1/2 of timeout */
+	wdd->pretimeout = timeout / 2;
+
+	writel_relaxed(((u64)f->freq / 2) * timeout, f->ctrl_base + WOR);
+
+	return 0;
+}
+
+static int sse_wdt_set_pretimeout(struct watchdog_device *wdd, unsigned int timeout)
+{
+	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
+
+	if (!timeout)
+		return -EINVAL;
+
+	/* pretimeout should not exceed 1/2 of max_timeout */
+	if (timeout * 2 <= f->wdd.max_timeout)
+		return sse_wdt_set_timeout(wdd, timeout * 2);
+
+	return -EINVAL;
+}
+
+static int sse_wdt_ping(struct watchdog_device *wdd)
+{
+	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
+
+	writel_relaxed(0, f->refr_base + WRR);
+
+	return 0;
+}
+
+static int sse_wdt_start(struct watchdog_device *wdd)
+{
+	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
+
+	writel_relaxed(WCS_EN, f->ctrl_base + WCS);
+
+	return 0;
+}
+
+static int sse_wdt_stop(struct watchdog_device *wdd)
+{
+	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
+
+	writel_relaxed(0, f->ctrl_base + WCS);
+
+	return 0;
+}
+
+static const struct watchdog_info sse_wdt_info = {
+	.identity	= "ARM SSE Watchdog",
+	.options	= WDIOF_SETTIMEOUT |
+			  WDIOF_PRETIMEOUT |
+			  WDIOF_KEEPALIVEPING |
+			  WDIOF_MAGICCLOSE |
+			  WDIOF_CARDRESET,
+};
+
+static const struct watchdog_ops sse_wdt_ops = {
+	.owner		= THIS_MODULE,
+	.start		= sse_wdt_start,
+	.stop		= sse_wdt_stop,
+	.ping		= sse_wdt_ping,
+	.set_timeout	= sse_wdt_set_timeout,
+	.set_pretimeout	= sse_wdt_set_pretimeout,
+};
+
+static int sse_setup_wdt(struct device *dev, struct sse_wdt_frame *f, unsigned long rate)
+{
+	u32 val;
+	int ret;
+	unsigned int max_pretimeout, timeout = SSE_WDT_DEFAULT_SECONDS;
+
+	f->freq = rate;
+	f->wdd.info = &sse_wdt_info;
+	f->wdd.ops = &sse_wdt_ops;
+	f->wdd.parent = dev;
+
+	max_pretimeout = U32_MAX / f->freq;
+	/* Maximum timeout is twice the pretimeout */
+	f->wdd.max_timeout = max_pretimeout * 2;
+	f->wdd.max_hw_heartbeat_ms = max_pretimeout * 1000;
+	/* Minimum first timeout (pretimeout) is 1, so min_timeout as 2 */
+	f->wdd.min_timeout = 2;
+
+	val = readl_relaxed(f->ctrl_base + WCS);
+	if (val & WCS_WS1) {
+		dev_warn(dev, "System reset by WDT.\n");
+		f->wdd.bootstatus |= WDIOF_CARDRESET;
+	}
+
+	if (val & WCS_EN) {
+		timeout = readl_relaxed(f->ctrl_base + WOR) / 2 / f->freq;
+		set_bit(WDOG_HW_RUNNING, &f->wdd.status);
+	}
+
+	watchdog_set_drvdata(&f->wdd, f);
+	watchdog_set_nowayout(&f->wdd, nowayout);
+	watchdog_init_timeout(&f->wdd, timeout, dev);
+	watchdog_stop_on_reboot(&f->wdd);
+	watchdog_stop_on_unregister(&f->wdd);
+
+	ret = devm_watchdog_register_device(dev, &f->wdd);
+	if (ret)
+		return ret;
+
+	ret = devm_request_irq(dev, f->irq, sse_wdt_interrupt, 0, "sse-wdt", f);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to register interrupt handler\n");
+
+	return 0;
+}
+
+static int sse_timer_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct sse_timer *sse;
+	unsigned long rate;
+	int i, j, ret;
+
+	sse = devm_kzalloc(&pdev->dev, sizeof(*sse), GFP_KERNEL);
+	if (!sse)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, sse);
+
+	sse->cntctrl_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(sse->cntctrl_base)) {
+		dev_err(&pdev->dev, "Can't map registers\n");
+		return PTR_ERR(sse->cntctrl_base);
+	}
+
+	sse->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+	if (IS_ERR(sse->clk)) {
+		dev_err(&pdev->dev, "Can't get timer clock\n");
+		return PTR_ERR(sse->clk);
+	}
+
+	rate = clk_get_rate(sse->clk);
+	if (!rate) {
+		dev_err(&pdev->dev, "Couldn't get parent clock rate\n");
+		return -EINVAL;
+	}
+
+	for_each_available_child_of_node_scoped(np, frame_node) {
+		const __be32 *addr = of_get_address(frame_node, 1, NULL, NULL);
+
+		if (!addr)
+			sse->timer_num++;
+		else
+			sse->wdt_num++;
+	}
+
+	sse->timers = devm_kcalloc(&pdev->dev, sse->timer_num, sizeof(*sse->timers), GFP_KERNEL);
+	if (!sse->timers)
+		return -ENOMEM;
+	sse->wdts = devm_kcalloc(&pdev->dev, sse->wdt_num, sizeof(*sse->wdts), GFP_KERNEL);
+	if (!sse->wdts)
+		return -ENOMEM;
+
+	writel_relaxed(0, sse->cntctrl_base + CNTCR);
+	writeq_relaxed(0, sse->cntctrl_base + CNTCV);
+	writel_relaxed(1, sse->cntctrl_base + CNTCR);
+
+	i = j = 0;
+	for_each_available_child_of_node_scoped(np, frame_node) {
+		struct resource res;
+		void __iomem *base;
+		const __be32 *addr;
+
+		ret = of_address_to_resource(frame_node, 0, &res);
+		if (ret < 0)
+			return ret;
+		base = devm_ioremap_resource(&pdev->dev, &res);
+		if (IS_ERR(base))
+			return PTR_ERR(base);
+
+		addr = of_get_address(frame_node, 1, NULL, NULL);
+		if (!addr) {
+			sse->timers[i].base = base;
+
+			ret = of_irq_get(frame_node, 0);
+			if (ret < 0)
+				return ret;
+			sse->timers[i].irq = ret;
+			i++;
+		} else {
+			sse->wdts[j].ctrl_base = base;
+
+			ret = of_address_to_resource(frame_node, 1, &res);
+			if (ret < 0)
+				return ret;
+			sse->wdts[j].refr_base = devm_ioremap_resource(&pdev->dev, &res);
+			if (IS_ERR(sse->wdts[j].refr_base))
+				return PTR_ERR(sse->wdts[j].refr_base);
+
+			ret = of_irq_get(frame_node, 0);
+			if (ret < 0)
+				return ret;
+			sse->wdts[j].irq = ret;
+			j++;
+		}
+	}
+
+	if (IS_ENABLED(CONFIG_WATCHDOG)) {
+		for (i = 0; i < sse->wdt_num; i++) {
+			ret = sse_setup_wdt(&pdev->dev, &sse->wdts[i], rate);
+			if (ret)
+				return ret;
+		}
+	}
+
+	for (i = 0; i < sse->timer_num; i++) {
+		ret = sse_setup_clocksource(&pdev->dev, &sse->timers[i], rate);
+		if (ret)
+			goto err_unreg_clocksource;
+	}
+
+	if (sse->timer_num > 0) {
+		ret = sse_setup_clockevent(&pdev->dev, &sse->timers[0], rate);
+		if (ret)
+			goto err_unreg_clocksource;
+	}
+
+	return 0;
+
+err_unreg_clocksource:
+	for (j = 0; j < i; j++)
+		clocksource_unregister(&sse->timers[j].cs);
+	return ret;
+}
+
+static const struct of_device_id sse_timer_of_match[] = {
+	{ .compatible = "arm,sse-timer" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, sse_timer_of_match);
+
+static struct platform_driver sse_timer_driver = {
+	.probe		= sse_timer_probe,
+	.driver	= {
+		.name	= "sse-timer",
+		.of_match_table = sse_timer_of_match,
+	},
+};
+module_platform_driver(sse_timer_driver);
+
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_DESCRIPTION("ARM SSE system timer driver");
+MODULE_LICENSE("GPL");
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver
  2025-08-21 15:24 ` [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver Jisheng Zhang
@ 2025-08-21 15:52   ` Jisheng Zhang
  2025-08-22  9:43   ` kernel test robot
  1 sibling, 0 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-21 15:52 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	linux-arm-kernel, linux-watchdog@vger.kernel.org Conor Dooley
  Cc: linux-kernel, devicetree

On Thu, Aug 21, 2025 at 11:24:29PM +0800, Jisheng Zhang wrote:
> Here is the ARM SSE(Subsystems for Embedded) timer doc URL:
> https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en
> 
> Although the IP is mostly seen on MCU SoC platforms, but nothing
> prevent it from being integrated into linux capable SoC platforms.
> 
> The IP core may have a system counter to generate timestamp value,
> a system timer to raise an interrupt when a period has elapsed, and
> a System Watchdog to detect errant system behaviour then reset the
> system if a period elapses without ping.
> 
> The differences between this IP and arm mmio arch timer include not
> limit to:
> 1. The system can add the timer frames as many as it want, I.E no
> up to 8 timer frames limitation at all.
> 2. The IP supports watchdog.
> 3. physical timer only.
> 4. The system counter can be exposed to so can be under the control of
>    linux.
> 
> Introduce a clocksource+watchdog driver for the ARM SSE timer IP.

+ arm and wdt maillist
> 
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  drivers/clocksource/Kconfig     |   7 +
>  drivers/clocksource/Makefile    |   1 +
>  drivers/clocksource/timer-sse.c | 540 ++++++++++++++++++++++++++++++++
>  3 files changed, 548 insertions(+)
>  create mode 100644 drivers/clocksource/timer-sse.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 645f517a1ac2..bfcbd7a1a498 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -152,6 +152,13 @@ config REALTEK_OTTO_TIMER
>  	  RT8391, RTL8392, RTL8393 and RTL8396 and chips of the RTL930x series
>  	  such as RTL9301, RTL9302 or RTL9303.
>  
> +config SSE_TIMER
> +	bool "ARM SSE(Subsystems for Embedded) system timer driver"
> +	depends on COMMON_CLK
> +	default n
> +	help
> +	  Enables support for the ARM SSE(Subsystems for Embedded) system timer driver.
> +
>  config SUN4I_TIMER
>  	bool "Sun4i timer driver" if COMPILE_TEST
>  	depends on HAS_IOMEM
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index 205bf3b0a8f3..dd688807694d 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_BCM2835_TIMER)	+= bcm2835_timer.o
>  obj-$(CONFIG_CLPS711X_TIMER)	+= clps711x-timer.o
>  obj-$(CONFIG_MXS_TIMER)		+= mxs_timer.o
>  obj-$(CONFIG_CLKSRC_PXA)	+= timer-pxa.o
> +obj-$(CONFIG_SSE_TIMER)		+= timer-sse.o
>  obj-$(CONFIG_SUN4I_TIMER)	+= timer-sun4i.o
>  obj-$(CONFIG_SUN5I_HSTIMER)	+= timer-sun5i.o
>  obj-$(CONFIG_MESON6_TIMER)	+= timer-meson6.o
> diff --git a/drivers/clocksource/timer-sse.c b/drivers/clocksource/timer-sse.c
> new file mode 100644
> index 000000000000..cf7d0bf07c2e
> --- /dev/null
> +++ b/drivers/clocksource/timer-sse.c
> @@ -0,0 +1,540 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2025 Synaptics Incorporated
> + *
> + * Author: Jisheng Zhang <jszhang@kernel.org>
> + *
> + * Some code are borrow from
> + * linux/drivers/clocksource/arm_arch_timer.c
> + * Copyright (C) 2011 ARM Ltd.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clockchips.h>
> +#include <linux/clocksource.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/io-64-nonatomic-lo-hi.h>
> +#include <linux/irq.h>
> +#include <linux/irqreturn.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +#include <linux/watchdog.h>
> +
> +#define CNTCR				0x00
> +#define CNTCV				0x08
> +
> +#define CNTPCT				0x00
> +#define CNTP_CVAL			0x20
> +#define CNTP_CTL			0x2c
> +#define  CNTP_CTL_ENABLE		BIT(0)
> +#define  CNTP_CTL_IMASK			BIT(1)
> +#define  CNTP_CTL_ISTATUS		BIT(2)
> +#define CNTP_AIVAL_RELOAD		0x48
> +#define CNTP_AIVAL_CTL			0x4c
> +#define  CNTP_AIVAL_CTL_EN		BIT(0)
> +#define  CNTP_AIVAL_CTL_CLR		BIT(1)
> +#define CNTP_CFG			0x50
> +#define  CNTP_CFG_AIVAL_MASK		GENMASK(3, 0)
> +#define  CNTP_CFG_AIVAL_IMPL		1
> +
> +#define WCS				0x00
> +#define  WCS_EN				BIT(0)
> +#define  WCS_WS0			BIT(1)
> +#define  WCS_WS1			BIT(2)
> +#define WOR				0x08
> +#define WCV				0x10
> +
> +#define WRR				0x00
> +
> +#define SSE_WDT_DEFAULT_SECONDS		30
> +
> +enum sse_timer_mode {
> +	SSE_TIMER_NORMAL,
> +	SSE_TIMER_AUTOINC,
> +};
> +
> +struct sse_timer_frame {
> +	void __iomem *base;
> +	struct clocksource cs;
> +	struct clock_event_device ce;
> +	u32 ticks_per_jiffy;
> +	int irq;
> +	enum sse_timer_mode mode;
> +};
> +
> +struct sse_wdt_frame {
> +	struct watchdog_device wdd;
> +	void __iomem *ctrl_base;
> +	void __iomem *refr_base;
> +	unsigned long freq;
> +	int irq;
> +};
> +
> +struct sse_timer {
> +	void __iomem *cntctrl_base;
> +	struct clk *clk;
> +	struct sse_timer_frame *timers;
> +	struct sse_wdt_frame *wdts;
> +	int timer_num;
> +	int wdt_num;
> +};
> +
> +#define cs_to_sse_timer_frame(x) \
> +	container_of(x, struct sse_timer_frame, cs)
> +#define ce_to_sse_timer_frame(x) \
> +	container_of(x, struct sse_timer_frame, ce)
> +
> +static bool nowayout = WATCHDOG_NOWAYOUT;
> +module_param(nowayout, bool, 0444);
> +MODULE_PARM_DESC(nowayout,
> +		 "Watchdog cannot be stopped once started (default="
> +		 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> +
> +static __always_inline u64 sse_get_cntpct(struct sse_timer_frame *f)
> +{
> +#ifndef CONFIG_64BIT
> +	u32 cnt_lo, cnt_hi, tmp_hi;
> +
> +	do {
> +		cnt_hi = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT + 4));
> +		cnt_lo = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT));
> +		tmp_hi = __le32_to_cpu((__le32 __force)__raw_readl(f->base + CNTPCT + 4));
> +	} while (cnt_hi != tmp_hi);
> +
> +	return ((u64) cnt_hi << 32) | cnt_lo;
> +#else
> +	return readq_relaxed(f->base + CNTPCT);
> +#endif
> +
> +}
> +
> +static int sse_ce_shutdown(struct clock_event_device *ce)
> +{
> +	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
> +	u32 val;
> +
> +	val = readl_relaxed(f->base + CNTP_CTL);
> +	val &= ~CNTP_CTL_ENABLE;
> +	writel_relaxed(val, f->base + CNTP_CTL);
> +	return 0;
> +}
> +
> +static int sse_ce_set_oneshot(struct clock_event_device *ce)
> +{
> +	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
> +	u32 val;
> +
> +	f->mode = SSE_TIMER_NORMAL;
> +
> +	val = readl_relaxed(f->base + CNTP_CTL);
> +	if (val & CNTP_CTL_ENABLE) {
> +		val &= ~CNTP_CTL_ENABLE;
> +		writel_relaxed(val, f->base + CNTP_CTL);
> +	}
> +
> +	writel_relaxed(0, f->base + CNTP_AIVAL_CTL);
> +
> +	return 0;
> +}
> +
> +static int sse_ce_set_periodic(struct clock_event_device *ce)
> +{
> +	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
> +	u32 val;
> +
> +	f->mode = SSE_TIMER_AUTOINC;
> +
> +	val = readl_relaxed(f->base + CNTP_CTL);
> +	if (val & CNTP_CTL_ENABLE) {
> +		val &= ~CNTP_CTL_ENABLE;
> +		writel_relaxed(val, f->base + CNTP_CTL);
> +	}
> +
> +	val |= CNTP_CTL_ENABLE;
> +	val &= ~CNTP_CTL_IMASK;
> +
> +	writel_relaxed(f->ticks_per_jiffy, f->base + CNTP_AIVAL_RELOAD);
> +	writel_relaxed(CNTP_AIVAL_CTL_EN, f->base + CNTP_AIVAL_CTL);
> +	writel_relaxed(val, f->base + CNTP_CTL);
> +
> +	return 0;
> +}
> +
> +static int sse_ce_next_event(unsigned long evt, struct clock_event_device *ce)
> +{
> +	struct sse_timer_frame *f = ce_to_sse_timer_frame(ce);
> +	u32 val;
> +	u64 cnt;
> +
> +	val = readl_relaxed(f->base + CNTP_CTL);
> +	if (val & CNTP_CTL_ENABLE) {
> +		val &= ~CNTP_CTL_ENABLE;
> +		writel_relaxed(val, f->base + CNTP_CTL);
> +	}
> +
> +	val |= CNTP_CTL_ENABLE;
> +	val &= ~CNTP_CTL_IMASK;
> +
> +	cnt = sse_get_cntpct(f);
> +	writeq_relaxed(evt + cnt, f->base + CNTP_CVAL);
> +	writel_relaxed(val, f->base + CNTP_CTL);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t sse_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct sse_timer_frame *f = dev_id;
> +	u32 val;
> +
> +	val = readl_relaxed(f->base + CNTP_CTL);
> +	if (!(val & CNTP_CTL_ISTATUS))
> +		return IRQ_NONE;
> +
> +	if (f->mode == SSE_TIMER_AUTOINC) {
> +		val = readl_relaxed(f->base + CNTP_AIVAL_CTL);
> +		val &= ~CNTP_AIVAL_CTL_CLR;
> +		writel_relaxed(val, f->base + CNTP_AIVAL_CTL);
> +	} else {
> +		val |= CNTP_CTL_IMASK;
> +		writel_relaxed(val, f->base + CNTP_CTL);
> +	}
> +	f->ce.event_handler(&f->ce);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int sse_setup_clockevent(struct device *dev, struct sse_timer_frame *f,
> +				unsigned long rate)
> +{
> +	int ret;
> +	u32 val = readl_relaxed(f->base + CNTP_CFG);
> +
> +	f->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
> +
> +	f->ce.name = "sse-timer";
> +	f->ce.rating = 300;
> +	f->ce.irq = f->irq;
> +	f->ce.cpumask = cpu_possible_mask;
> +	f->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
> +	f->ce.set_state_shutdown = sse_ce_shutdown;
> +	f->ce.set_next_event = sse_ce_next_event;
> +	f->ce.set_state_oneshot_stopped = sse_ce_shutdown;
> +	if (FIELD_GET(CNTP_CFG_AIVAL_MASK, val) == CNTP_CFG_AIVAL_IMPL) {
> +		f->ce.set_state_periodic = sse_ce_set_periodic;
> +		f->ce.set_state_oneshot = sse_ce_set_oneshot;
> +	}
> +
> +	clockevents_config_and_register(&f->ce, rate, 0xf, ULONG_MAX);
> +
> +	ret = devm_request_irq(dev, f->irq, sse_timer_interrupt,
> +			       IRQF_TIMER | IRQF_NOBALANCING,
> +			       f->ce.name, f);
> +	if (ret) {
> +		dev_err(dev, "Unable to register interrupt\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static noinstr u64 cs_sse_get_cntpct(struct clocksource *cs)
> +{
> +	struct sse_timer_frame *f = cs_to_sse_timer_frame(cs);
> +
> +	return sse_get_cntpct(f);
> +}
> +
> +static int sse_setup_clocksource(struct device *dev, struct sse_timer_frame *f,
> +				 unsigned long rate)
> +{
> +	int ret;
> +
> +	f->cs.name = "sse-timer";
> +	f->cs.rating = 300;
> +	f->cs.read = cs_sse_get_cntpct;
> +	f->cs.mask = CLOCKSOURCE_MASK(64);
> +	f->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
> +
> +	ret = clocksource_register_hz(&f->cs, rate);
> +	if (ret) {
> +		dev_err(dev, "Couldn't register clock source.\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t sse_wdt_interrupt(int irq, void *dev_id)
> +{
> +	struct sse_wdt_frame *f = dev_id;
> +	u32 val;
> +
> +	val = readl_relaxed(f->ctrl_base + WCS);
> +	if (val & WCS_WS0)
> +		watchdog_notify_pretimeout(&f->wdd);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int sse_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
> +{
> +	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
> +
> +	wdd->timeout = timeout;
> +
> +	/* Pretimeout is 1/2 of timeout */
> +	wdd->pretimeout = timeout / 2;
> +
> +	writel_relaxed(((u64)f->freq / 2) * timeout, f->ctrl_base + WOR);
> +
> +	return 0;
> +}
> +
> +static int sse_wdt_set_pretimeout(struct watchdog_device *wdd, unsigned int timeout)
> +{
> +	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
> +
> +	if (!timeout)
> +		return -EINVAL;
> +
> +	/* pretimeout should not exceed 1/2 of max_timeout */
> +	if (timeout * 2 <= f->wdd.max_timeout)
> +		return sse_wdt_set_timeout(wdd, timeout * 2);
> +
> +	return -EINVAL;
> +}
> +
> +static int sse_wdt_ping(struct watchdog_device *wdd)
> +{
> +	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
> +
> +	writel_relaxed(0, f->refr_base + WRR);
> +
> +	return 0;
> +}
> +
> +static int sse_wdt_start(struct watchdog_device *wdd)
> +{
> +	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
> +
> +	writel_relaxed(WCS_EN, f->ctrl_base + WCS);
> +
> +	return 0;
> +}
> +
> +static int sse_wdt_stop(struct watchdog_device *wdd)
> +{
> +	struct sse_wdt_frame *f = watchdog_get_drvdata(wdd);
> +
> +	writel_relaxed(0, f->ctrl_base + WCS);
> +
> +	return 0;
> +}
> +
> +static const struct watchdog_info sse_wdt_info = {
> +	.identity	= "ARM SSE Watchdog",
> +	.options	= WDIOF_SETTIMEOUT |
> +			  WDIOF_PRETIMEOUT |
> +			  WDIOF_KEEPALIVEPING |
> +			  WDIOF_MAGICCLOSE |
> +			  WDIOF_CARDRESET,
> +};
> +
> +static const struct watchdog_ops sse_wdt_ops = {
> +	.owner		= THIS_MODULE,
> +	.start		= sse_wdt_start,
> +	.stop		= sse_wdt_stop,
> +	.ping		= sse_wdt_ping,
> +	.set_timeout	= sse_wdt_set_timeout,
> +	.set_pretimeout	= sse_wdt_set_pretimeout,
> +};
> +
> +static int sse_setup_wdt(struct device *dev, struct sse_wdt_frame *f, unsigned long rate)
> +{
> +	u32 val;
> +	int ret;
> +	unsigned int max_pretimeout, timeout = SSE_WDT_DEFAULT_SECONDS;
> +
> +	f->freq = rate;
> +	f->wdd.info = &sse_wdt_info;
> +	f->wdd.ops = &sse_wdt_ops;
> +	f->wdd.parent = dev;
> +
> +	max_pretimeout = U32_MAX / f->freq;
> +	/* Maximum timeout is twice the pretimeout */
> +	f->wdd.max_timeout = max_pretimeout * 2;
> +	f->wdd.max_hw_heartbeat_ms = max_pretimeout * 1000;
> +	/* Minimum first timeout (pretimeout) is 1, so min_timeout as 2 */
> +	f->wdd.min_timeout = 2;
> +
> +	val = readl_relaxed(f->ctrl_base + WCS);
> +	if (val & WCS_WS1) {
> +		dev_warn(dev, "System reset by WDT.\n");
> +		f->wdd.bootstatus |= WDIOF_CARDRESET;
> +	}
> +
> +	if (val & WCS_EN) {
> +		timeout = readl_relaxed(f->ctrl_base + WOR) / 2 / f->freq;
> +		set_bit(WDOG_HW_RUNNING, &f->wdd.status);
> +	}
> +
> +	watchdog_set_drvdata(&f->wdd, f);
> +	watchdog_set_nowayout(&f->wdd, nowayout);
> +	watchdog_init_timeout(&f->wdd, timeout, dev);
> +	watchdog_stop_on_reboot(&f->wdd);
> +	watchdog_stop_on_unregister(&f->wdd);
> +
> +	ret = devm_watchdog_register_device(dev, &f->wdd);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_request_irq(dev, f->irq, sse_wdt_interrupt, 0, "sse-wdt", f);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "Failed to register interrupt handler\n");
> +
> +	return 0;
> +}
> +
> +static int sse_timer_probe(struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct sse_timer *sse;
> +	unsigned long rate;
> +	int i, j, ret;
> +
> +	sse = devm_kzalloc(&pdev->dev, sizeof(*sse), GFP_KERNEL);
> +	if (!sse)
> +		return -ENOMEM;
> +
> +	platform_set_drvdata(pdev, sse);
> +
> +	sse->cntctrl_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(sse->cntctrl_base)) {
> +		dev_err(&pdev->dev, "Can't map registers\n");
> +		return PTR_ERR(sse->cntctrl_base);
> +	}
> +
> +	sse->clk = devm_clk_get_enabled(&pdev->dev, NULL);
> +	if (IS_ERR(sse->clk)) {
> +		dev_err(&pdev->dev, "Can't get timer clock\n");
> +		return PTR_ERR(sse->clk);
> +	}
> +
> +	rate = clk_get_rate(sse->clk);
> +	if (!rate) {
> +		dev_err(&pdev->dev, "Couldn't get parent clock rate\n");
> +		return -EINVAL;
> +	}
> +
> +	for_each_available_child_of_node_scoped(np, frame_node) {
> +		const __be32 *addr = of_get_address(frame_node, 1, NULL, NULL);
> +
> +		if (!addr)
> +			sse->timer_num++;
> +		else
> +			sse->wdt_num++;
> +	}
> +
> +	sse->timers = devm_kcalloc(&pdev->dev, sse->timer_num, sizeof(*sse->timers), GFP_KERNEL);
> +	if (!sse->timers)
> +		return -ENOMEM;
> +	sse->wdts = devm_kcalloc(&pdev->dev, sse->wdt_num, sizeof(*sse->wdts), GFP_KERNEL);
> +	if (!sse->wdts)
> +		return -ENOMEM;
> +
> +	writel_relaxed(0, sse->cntctrl_base + CNTCR);
> +	writeq_relaxed(0, sse->cntctrl_base + CNTCV);
> +	writel_relaxed(1, sse->cntctrl_base + CNTCR);
> +
> +	i = j = 0;
> +	for_each_available_child_of_node_scoped(np, frame_node) {
> +		struct resource res;
> +		void __iomem *base;
> +		const __be32 *addr;
> +
> +		ret = of_address_to_resource(frame_node, 0, &res);
> +		if (ret < 0)
> +			return ret;
> +		base = devm_ioremap_resource(&pdev->dev, &res);
> +		if (IS_ERR(base))
> +			return PTR_ERR(base);
> +
> +		addr = of_get_address(frame_node, 1, NULL, NULL);
> +		if (!addr) {
> +			sse->timers[i].base = base;
> +
> +			ret = of_irq_get(frame_node, 0);
> +			if (ret < 0)
> +				return ret;
> +			sse->timers[i].irq = ret;
> +			i++;
> +		} else {
> +			sse->wdts[j].ctrl_base = base;
> +
> +			ret = of_address_to_resource(frame_node, 1, &res);
> +			if (ret < 0)
> +				return ret;
> +			sse->wdts[j].refr_base = devm_ioremap_resource(&pdev->dev, &res);
> +			if (IS_ERR(sse->wdts[j].refr_base))
> +				return PTR_ERR(sse->wdts[j].refr_base);
> +
> +			ret = of_irq_get(frame_node, 0);
> +			if (ret < 0)
> +				return ret;
> +			sse->wdts[j].irq = ret;
> +			j++;
> +		}
> +	}
> +
> +	if (IS_ENABLED(CONFIG_WATCHDOG)) {
> +		for (i = 0; i < sse->wdt_num; i++) {
> +			ret = sse_setup_wdt(&pdev->dev, &sse->wdts[i], rate);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	for (i = 0; i < sse->timer_num; i++) {
> +		ret = sse_setup_clocksource(&pdev->dev, &sse->timers[i], rate);
> +		if (ret)
> +			goto err_unreg_clocksource;
> +	}
> +
> +	if (sse->timer_num > 0) {
> +		ret = sse_setup_clockevent(&pdev->dev, &sse->timers[0], rate);
> +		if (ret)
> +			goto err_unreg_clocksource;
> +	}
> +
> +	return 0;
> +
> +err_unreg_clocksource:
> +	for (j = 0; j < i; j++)
> +		clocksource_unregister(&sse->timers[j].cs);
> +	return ret;
> +}
> +
> +static const struct of_device_id sse_timer_of_match[] = {
> +	{ .compatible = "arm,sse-timer" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, sse_timer_of_match);
> +
> +static struct platform_driver sse_timer_driver = {
> +	.probe		= sse_timer_probe,
> +	.driver	= {
> +		.name	= "sse-timer",
> +		.of_match_table = sse_timer_of_match,
> +	},
> +};
> +module_platform_driver(sse_timer_driver);
> +
> +MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
> +MODULE_DESCRIPTION("ARM SSE system timer driver");
> +MODULE_LICENSE("GPL");
> -- 
> 2.50.1
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
@ 2025-08-21 15:55   ` Jisheng Zhang
  2025-08-21 22:39   ` Rob Herring (Arm)
  2025-08-22  7:21   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-21 15:55 UTC (permalink / raw)
  To: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-watchdog, linux-arm-kernel
  Cc: linux-kernel, devicetree

On Thu, Aug 21, 2025 at 11:24:28PM +0800, Jisheng Zhang wrote:
> Add binding doc for the ARM SSE(Subsystems for Embedded) timer. Here
> is the document URL:
> https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en
> 
> Although the IP is mostly seen on MCU SoC platforms, but nothing
> prevent it from being integrated into linux capable SoC platforms.
> 
> The IP core may have a system counter to generate timestamp value,
> a system timer to raise an interrupt when a period has elapsed, and
> a System Watchdog to detect errant system behaviour then reset the
> system if a period elapses without ping.
> 
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  .../bindings/timer/arm,sse_timer.yaml         | 90 +++++++++++++++++++
>  1 file changed, 90 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> 
> diff --git a/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> new file mode 100644
> index 000000000000..37a79f9052d0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> @@ -0,0 +1,90 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/timer/arm,sse_timer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ARM SSE(Subsystems for Embedded) system timer
> +
> +maintainers:
> +  - Jisheng Zhang <jszhang@kernel.org>
> +
> +description: |+
> +  ARM SSE(Subsystems for Embedded) system timer core may have a system counter
> +  to generate timestamp value, a system timer to raise an interrupt when a
> +  period has elapsed, and a System Watchdog to detect errant system behaviour
> +  then reset the system if a period elapses without ping.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - arm,sse-timer
> +
> +  reg:
> +    maxItems: 1
> +    description: The system counter control frame base
> +
> +  clocks:
> +    maxItems: 1
> +
> +  '#address-cells':
> +    enum: [1, 2]
> +
> +  '#size-cells':
> +    const: 1
> +
> +  ranges: true
> +
> +patternProperties:
> +  '^frame@[0-9a-f]+$':
> +    type: object
> +    additionalProperties: false
> +    description: A timer node has some frame sub-nodes, each frame can be timer frame or watchdog frame. Each frame has the following properties.
> +    properties:
> +      interrupts:
> +        minItems: 1
> +        items:
> +          - description: timer irq
> +
> +      reg:
> +        minItems: 1
> +        items:
> +          - description: 1st view base address
> +          - description: 2nd optional view base address if this is a watchdog frame
> +
> +    required:
> +      - interrupts
> +      - reg
> +
> +required:
> +  - compatible
> +  - reg
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    timer@f7f3e000 {
> +      compatible = "arm,sse-timer";
> +      #address-cells = <1>;
> +      #size-cells = <1>;
> +      ranges;
> +      reg = <0xf7f3e000 0x2000>;
> +      clocks = <&core_clk>;
> +
> +      frame@f7f20000 {
> +        reg = <0xf7f20000 0x1000>;
> +        interrupts = <0 26 0x8>;
> +      };
> +
> +      frame@f7f30000 {
> +        interrupts = <0 15 0x8>;
> +        reg = <0xf7f32000 0x1000>,
> +              <0xf7f33000 0x1000>;
> +      };
> +    };
> +
> +...
> -- 
> 2.50.1
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
  2025-08-21 15:55   ` Jisheng Zhang
@ 2025-08-21 22:39   ` Rob Herring (Arm)
  2025-08-22  0:41     ` Jisheng Zhang
  2025-08-22  7:21   ` Krzysztof Kozlowski
  2 siblings, 1 reply; 9+ messages in thread
From: Rob Herring (Arm) @ 2025-08-21 22:39 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Daniel Lezcano, linux-kernel, Thomas Gleixner, devicetree,
	Krzysztof Kozlowski, Conor Dooley


On Thu, 21 Aug 2025 23:24:28 +0800, Jisheng Zhang wrote:
> Add binding doc for the ARM SSE(Subsystems for Embedded) timer. Here
> is the document URL:
> https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en
> 
> Although the IP is mostly seen on MCU SoC platforms, but nothing
> prevent it from being integrated into linux capable SoC platforms.
> 
> The IP core may have a system counter to generate timestamp value,
> a system timer to raise an interrupt when a period has elapsed, and
> a System Watchdog to detect errant system behaviour then reset the
> system if a period elapses without ping.
> 
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  .../bindings/timer/arm,sse_timer.yaml         | 90 +++++++++++++++++++
>  1 file changed, 90 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:
./Documentation/devicetree/bindings/timer/arm,sse_timer.yaml:43:111: [warning] line too long (145 > 110 characters) (line-length)

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml: patternProperties:^frame@[0-9a-f]+$:properties:interrupts: 'oneOf' conditional failed, one must be fixed:
	[{'description': 'timer irq'}] is too short
	False schema does not allow 1
	hint: "minItems" is only needed if less than the "items" list length
	from schema $id: http://devicetree.org/meta-schemas/items.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250821152429.26995-2-jszhang@kernel.org

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  2025-08-21 22:39   ` Rob Herring (Arm)
@ 2025-08-22  0:41     ` Jisheng Zhang
  0 siblings, 0 replies; 9+ messages in thread
From: Jisheng Zhang @ 2025-08-22  0:41 UTC (permalink / raw)
  To: Rob Herring (Arm)
  Cc: Daniel Lezcano, linux-kernel, Thomas Gleixner, devicetree,
	linux-watchdog,
	linux-arm-kernel@lists.infradead.org Krzysztof Kozlowski,
	Conor Dooley

On Thu, Aug 21, 2025 at 05:39:48PM -0500, Rob Herring (Arm) wrote:
> 
> On Thu, 21 Aug 2025 23:24:28 +0800, Jisheng Zhang wrote:
> > Add binding doc for the ARM SSE(Subsystems for Embedded) timer. Here
> > is the document URL:
> > https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en
> > 
> > Although the IP is mostly seen on MCU SoC platforms, but nothing
> > prevent it from being integrated into linux capable SoC platforms.
> > 
> > The IP core may have a system counter to generate timestamp value,
> > a system timer to raise an interrupt when a period has elapsed, and
> > a System Watchdog to detect errant system behaviour then reset the
> > system if a period elapses without ping.
> > 
> > Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> > ---
> >  .../bindings/timer/arm,sse_timer.yaml         | 90 +++++++++++++++++++
> >  1 file changed, 90 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> > 
> 
> My bot found errors running 'make dt_binding_check' on your patch:

Oops, thanks for the hint. I would like to collect feedbacks to the
implementation itself, then fix the dt errors/warnings in v2.

Thanks
> 
> yamllint warnings/errors:
> ./Documentation/devicetree/bindings/timer/arm,sse_timer.yaml:43:111: [warning] line too long (145 > 110 characters) (line-length)
> 
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml: patternProperties:^frame@[0-9a-f]+$:properties:interrupts: 'oneOf' conditional failed, one must be fixed:
> 	[{'description': 'timer irq'}] is too short
> 	False schema does not allow 1
> 	hint: "minItems" is only needed if less than the "items" list length
> 	from schema $id: http://devicetree.org/meta-schemas/items.yaml#
> 
> doc reference errors (make refcheckdocs):
> 
> See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250821152429.26995-2-jszhang@kernel.org
> 
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
> 
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
> 
> pip3 install dtschema --upgrade
> 
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer
  2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
  2025-08-21 15:55   ` Jisheng Zhang
  2025-08-21 22:39   ` Rob Herring (Arm)
@ 2025-08-22  7:21   ` Krzysztof Kozlowski
  2 siblings, 0 replies; 9+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-22  7:21 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Daniel Lezcano, Thomas Gleixner, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-kernel, devicetree

On Thu, Aug 21, 2025 at 11:24:28PM +0800, Jisheng Zhang wrote:
> Add binding doc for the ARM SSE(Subsystems for Embedded) timer. Here
> is the document URL:
> https://developer.arm.com/documentation/107610/0000/System-timer-components?lang=en
> 
> Although the IP is mostly seen on MCU SoC platforms, but nothing
> prevent it from being integrated into linux capable SoC platforms.

But is there such integration?

> 
> The IP core may have a system counter to generate timestamp value,
> a system timer to raise an interrupt when a period has elapsed, and
> a System Watchdog to detect errant system behaviour then reset the
> system if a period elapses without ping.
> 
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> ---
>  .../bindings/timer/arm,sse_timer.yaml         | 90 +++++++++++++++++++
>  1 file changed, 90 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> 
> diff --git a/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> new file mode 100644
> index 000000000000..37a79f9052d0
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/arm,sse_timer.yaml
> @@ -0,0 +1,90 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/timer/arm,sse_timer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ARM SSE(Subsystems for Embedded) system timer
> +
> +maintainers:
> +  - Jisheng Zhang <jszhang@kernel.org>
> +
> +description: |+

Drop |+

> +  ARM SSE(Subsystems for Embedded) system timer core may have a system counter
> +  to generate timestamp value, a system timer to raise an interrupt when a
> +  period has elapsed, and a System Watchdog to detect errant system behaviour
> +  then reset the system if a period elapses without ping.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:

Drop these two, just const.

> +          - arm,sse-timer
> +
> +  reg:
> +    maxItems: 1
> +    description: The system counter control frame base
> +
> +  clocks:
> +    maxItems: 1
> +
> +  '#address-cells':
> +    enum: [1, 2]
> +
> +  '#size-cells':
> +    const: 1
> +
> +  ranges: true
> +
> +patternProperties:
> +  '^frame@[0-9a-f]+$':
> +    type: object
> +    additionalProperties: false
> +    description: A timer node has some frame sub-nodes, each frame can be timer frame or watchdog frame. Each frame has the following properties.

Please follow Linux coding style.

> +    properties:
> +      interrupts:
> +        minItems: 1
Drop

> +        items:
> +          - description: timer irq

Drop, instead maxItems: 1

> +
> +      reg:

Keep order as in every other binding (and DTS coding style).

> +        minItems: 1
> +        items:
> +          - description: 1st view base address
> +          - description: 2nd optional view base address if this is a watchdog frame
> +
> +    required:
> +      - interrupts
> +      - reg

Keep DTS coding style order.

> +
> +required:
> +  - compatible
> +  - reg
> +  - '#address-cells'
> +  - '#size-cells'
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    timer@f7f3e000 {
> +      compatible = "arm,sse-timer";
> +      #address-cells = <1>;

Keep order as in DTS coding style.

> +      #size-cells = <1>;
> +      ranges;
> +      reg = <0xf7f3e000 0x2000>;
> +      clocks = <&core_clk>;
> +
> +      frame@f7f20000 {
> +        reg = <0xf7f20000 0x1000>;
> +        interrupts = <0 26 0x8>;

Use proper defines

> +      };
> +
> +      frame@f7f30000 {
> +        interrupts = <0 15 0x8>;
> +        reg = <0xf7f32000 0x1000>,
> +              <0xf7f33000 0x1000>;
> +      };

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver
  2025-08-21 15:24 ` [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver Jisheng Zhang
  2025-08-21 15:52   ` Jisheng Zhang
@ 2025-08-22  9:43   ` kernel test robot
  1 sibling, 0 replies; 9+ messages in thread
From: kernel test robot @ 2025-08-22  9:43 UTC (permalink / raw)
  To: Jisheng Zhang, Daniel Lezcano, Thomas Gleixner, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: oe-kbuild-all, linux-kernel, devicetree

Hi Jisheng,

kernel test robot noticed the following build errors:

[auto build test ERROR on tip/timers/core]
[also build test ERROR on robh/for-next linus/master v6.17-rc2 next-20250822]
[cannot apply to daniel-lezcano/clockevents/next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Jisheng-Zhang/dt-bindings-timer-Add-ARM-SSE-Subsystems-for-Embedded-timer/20250822-000122
base:   tip/timers/core
patch link:    https://lore.kernel.org/r/20250821152429.26995-3-jszhang%40kernel.org
patch subject: [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver
config: m68k-allmodconfig (https://download.01.org/0day-ci/archive/20250822/202508221736.qO3Ji6Dw-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250822/202508221736.qO3Ji6Dw-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508221736.qO3Ji6Dw-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/clocksource/timer-sse.c: In function 'sse_setup_clockevent':
>> drivers/clocksource/timer-sse.c:228:13: error: implicit declaration of function 'FIELD_GET' [-Wimplicit-function-declaration]
     228 |         if (FIELD_GET(CNTP_CFG_AIVAL_MASK, val) == CNTP_CFG_AIVAL_IMPL) {
         |             ^~~~~~~~~


vim +/FIELD_GET +228 drivers/clocksource/timer-sse.c

   211	
   212	static int sse_setup_clockevent(struct device *dev, struct sse_timer_frame *f,
   213					unsigned long rate)
   214	{
   215		int ret;
   216		u32 val = readl_relaxed(f->base + CNTP_CFG);
   217	
   218		f->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
   219	
   220		f->ce.name = "sse-timer";
   221		f->ce.rating = 300;
   222		f->ce.irq = f->irq;
   223		f->ce.cpumask = cpu_possible_mask;
   224		f->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
   225		f->ce.set_state_shutdown = sse_ce_shutdown;
   226		f->ce.set_next_event = sse_ce_next_event;
   227		f->ce.set_state_oneshot_stopped = sse_ce_shutdown;
 > 228		if (FIELD_GET(CNTP_CFG_AIVAL_MASK, val) == CNTP_CFG_AIVAL_IMPL) {
   229			f->ce.set_state_periodic = sse_ce_set_periodic;
   230			f->ce.set_state_oneshot = sse_ce_set_oneshot;
   231		}
   232	
   233		clockevents_config_and_register(&f->ce, rate, 0xf, ULONG_MAX);
   234	
   235		ret = devm_request_irq(dev, f->irq, sse_timer_interrupt,
   236				       IRQF_TIMER | IRQF_NOBALANCING,
   237				       f->ce.name, f);
   238		if (ret) {
   239			dev_err(dev, "Unable to register interrupt\n");
   240			return ret;
   241		}
   242	
   243		return 0;
   244	}
   245	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-08-22  9:44 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-21 15:24 [PATCH 0/2] clocksource: Support ARM SSE(Subsystems for Embedded) Jisheng Zhang
2025-08-21 15:24 ` [PATCH 1/2] dt-bindings: timer: Add ARM SSE(Subsystems for Embedded) timer Jisheng Zhang
2025-08-21 15:55   ` Jisheng Zhang
2025-08-21 22:39   ` Rob Herring (Arm)
2025-08-22  0:41     ` Jisheng Zhang
2025-08-22  7:21   ` Krzysztof Kozlowski
2025-08-21 15:24 ` [PATCH 2/2] clocksource/drivers: Add ARM SSE(Subsystems for Embedded) Timer driver Jisheng Zhang
2025-08-21 15:52   ` Jisheng Zhang
2025-08-22  9:43   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).