From nobody Tue Jun 16 06:05:23 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (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 73091253340; Thu, 16 Apr 2026 17:51:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776361875; cv=none; b=d0WYoVNZJFFW4jo5znjue04xn+9oD7UUUAzIaZRiN774Gzf3Zq8oyBH06HNbDk1D72Jx0spP2+D3HNK9u/TQJNGg44YPxIdhLubi4z4/2E/VFw2vCI/zMzKZbJryk+oIt/3qCz0T0VOXWSoCus8dI3P3fCpePaBSXBqD1BgUxDo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776361875; c=relaxed/simple; bh=LlTdgu7xpklfNJdbjEayTPx4kyGDXyAve+dyGyQtu2I=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FlcPed9/K/hlwbp3ngWITLN6P555R0PwuSEB2J1sIFlaGfDiZ2neVwmY9ZwEcG+sSPdG1uRkr/fN6TEJc0cuNGmyme21KKblMt4ZokYdSsq5jQzJGT9l9DPf6IN+qq9D4fzGkHyaPJ2lpvBhvYkCPy5yZB7talY8KXI4F0Rgg+c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=pass smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=Y1yHITel; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="Y1yHITel" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id F1049FD412; Thu, 16 Apr 2026 19:51:05 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1776361867; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=AxfSVxs5649KBWpRUEZiLQP9o0YA4S8QqYmLn9Xyq2A=; b=Y1yHITelWp6jVww88es0vS1HHRoeFYM90+RfYNqr1HFn5MuzOAfDE0f5tTlXQtcXbwrpJ9 xj2mFsC49ZipYZLkIrer+MeOHr51xI4bQIVEaZeBm7eqeug0dxR0WhenrhGLam9cSvu0ee Up+KCOLptCs5c/uC6ux3jX+VuVhajdbhyeFPHmO3ZJTVRQRUPjnnOKl/DwxURZtoRWMyyt VEzB2uHZPHP6CQM65ECbrthuZzI1UIlj8OB3Erho7Yc6f8K790JNrEcyYw+XvSxn00S25s 2FZGG8yF9U+Q4RhvlIOqPWEkFTTAotYE0kP/ltZmRKa33bJhJe3ZP94Lsfc+9w== From: Caleb James DeLisle To: linux-mips@vger.kernel.org Cc: naseefkm@gmail.com, daniel.lezcano@kernel.org, tglx@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Caleb James DeLisle Subject: [PATCH 1/2] dt-bindings: timer: econet: Update EN751627 for multi-IRQ Date: Thu, 16 Apr 2026 17:51:00 +0000 Message-Id: <20260416175101.958073-2-cjd@cjdns.fr> In-Reply-To: <20260416175101.958073-1-cjd@cjdns.fr> References: <20260416175101.958073-1-cjd@cjdns.fr> 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-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" From conception, this driver supported EN751627 as it is the same hardware that is used in EN751221. However, it was expected that EN751627 would use a percpu IRQ as does EN751221, this is how it works in vendor code. However upon finding that the "mti,gic" intc works on EN751627 with no modification - but it provides a unique interrupt per-timer, it is deemed best to make this driver use multiple IRQs when on the EN751627 platform. Signed-off-by: Caleb James DeLisle Acked-by: Conor Dooley --- .../bindings/timer/econet,en751221-timer.yaml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/timer/econet,en751221-timer.= yaml b/Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml index c1e7c2b6afde..f338739e039c 100644 --- a/Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml +++ b/Documentation/devicetree/bindings/timer/econet,en751221-timer.yaml @@ -28,8 +28,8 @@ properties: maxItems: 2 =20 interrupts: - maxItems: 1 - description: A percpu-devid timer interrupt shared across CPUs. + minItems: 1 + maxItems: 4 =20 clocks: maxItems: 1 @@ -52,21 +52,31 @@ allOf: items: - description: VPE timers 0 and 1 - description: VPE timers 2 and 3 + interrupts: + description: An interrupt for each timer (one per VPE) + minItems: 4 else: properties: reg: items: - description: VPE timers 0 and 1 + interrupts: + description: A percpu-devid timer interrupt shared across timers + maxItems: 1 =20 additionalProperties: false =20 examples: - | + #include timer@1fbf0400 { compatible =3D "econet,en751627-timer", "econet,en751221-timer"; reg =3D <0x1fbf0400 0x100>, <0x1fbe0000 0x100>; interrupt-parent =3D <&intc>; - interrupts =3D <30>; + interrupts =3D , + , + , + ; clocks =3D <&hpt_clock>; }; - | --=20 2.39.5 From nobody Tue Jun 16 06:05:23 2026 Received: from mail.cjdns.fr (mail.cjdns.fr [5.135.140.105]) (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 9E571322B7D; Thu, 16 Apr 2026 17:51:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=5.135.140.105 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776361878; cv=none; b=j7WmTq6R5uJ11KuUnS+2Go5gZC8ACjZwXYIMvuKUomy9xMw+q10tnujrFZkiI9AKdXGfur/qWlaiX5aU5j9J34oD7ogabWv7PYAq5DMzgm5XtXg14D97zU2rxNaaLYQN1qALzLWg1K3hVCbnDoRxSnITwfke36LOX+HeGrFnoSU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776361878; c=relaxed/simple; bh=n1mwyY11ooJjVMa1y3e0LBKRobsKQDCVDDmSs95TWUk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=bv5V5u115+GYURIFQHsQRm6kFqmDIY9AiVNZnbgFQPBL1tsOcRw5tcu2Un1+QoZgzY8vROf9dcO3LFRjQRpmE4ojz7EhUYIsXsIh59600mLBBtEy2xDfwVNb7r8IqgSE2LhRAnvn5yDD+ZSIvkL7Xksyw+bfXTJawBvHDMPXcV0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr; spf=pass smtp.mailfrom=cjdns.fr; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b=khL0DCG7; arc=none smtp.client-ip=5.135.140.105 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=cjdns.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cjdns.fr header.i=@cjdns.fr header.b="khL0DCG7" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 919C7FB7E9; Thu, 16 Apr 2026 19:51:07 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cjdns.fr; s=dkim; t=1776361868; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=jFEFBsckozMzj3hugoSbDEI2lfszgMQy6N4tJWS0jjg=; b=khL0DCG7YRgrXR33Zv4TxZELi85EwoQYYaZ8HxNte1FuYAeua+6q8VSwGnuuDVP9UxWqLR YMXJqRnnd0733PfrqxgAkdBw0fCuyy1HLt3fDV1ixbrMXSu+V4dzPlMm/bT1H5/aRh+Xh5 0dSTWfs5l3vrNeEPzESMAgntPUUurR1VCBBaMN6Nk9S+/l77UnI5QYdKIoAC4rHmVzegEA xASYa6T7I4TY80SXmm5+WsSj8BdXie3A+jhW2ASqKcz4ky4Cb7Er3JuFcjvZwxkscacL6x pHNT6pqXvq/9YBOt1ItKcvD7K1D2H/bZQwH8E6Mc7+Iu8iP+QHXj+BsZTaojIw== From: Caleb James DeLisle To: linux-mips@vger.kernel.org Cc: naseefkm@gmail.com, daniel.lezcano@kernel.org, tglx@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, Caleb James DeLisle Subject: [PATCH 2/2] clocksource/timer-econet-en751221: Support irq number per timer Date: Thu, 16 Apr 2026 17:51:01 +0000 Message-Id: <20260416175101.958073-3-cjd@cjdns.fr> In-Reply-To: <20260416175101.958073-1-cjd@cjdns.fr> References: <20260416175101.958073-1-cjd@cjdns.fr> 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-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" This timer was first developed on the EN751221 which is a MIPS 34Kc and therefore has a custom interrupt controller. The hardware for econet,en751221-intc implements percpu routing of the timer interrupts. However, the EN751627 and EN7528 are MIPS 1004Kc based, and therefore use the standard mti,gic compatible interrupt controller. This interrupt controller uses a different IRQ number for each timer interrupt. Add support for both models in this timer driver. Co-developed-by: Ahmed Naseef Signed-off-by: Ahmed Naseef Link: https://github.com/openwrt/openwrt/commit/fab098cb6121647ca9cc6e501d5= 6ebe8a9ea550b#diff-a09ee5e4166e89df337d03c1455dce7b81eb89797b1d0f714476b188= e6685334 [cjd@cjdns.fr minor changes: Set ECONET_MAX_IRQS to NR_CPUS rather than 4 Use is_percpu_irq() instead of field Do not set CLOCK_EVT_FEAT_PERCPU in non-percpu mode Fold cevt_init() into timer_init() ] Signed-off-by: Caleb James DeLisle --- drivers/clocksource/Kconfig | 5 +- drivers/clocksource/timer-econet-en751221.c | 137 ++++++++++++++++---- 2 files changed, 114 insertions(+), 28 deletions(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d1a33a231a44..9a77f38d5fb7 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -79,7 +79,10 @@ config ECONET_EN751221_TIMER select CLKSRC_MMIO select TIMER_OF help - Support for CPU timer found on EcoNet MIPS based SoCs. + Support for CPU timer found on EcoNet EN75xx MIPS based SoCs + (EN751221, EN751627, EN7528). The driver supports both GIC-based + (separate IRQ per CPU) and legacy interrupt controller (percpu IRQ) + modes. =20 config FTTMR010_TIMER bool "Faraday Technology timer driver" if COMPILE_TEST diff --git a/drivers/clocksource/timer-econet-en751221.c b/drivers/clocksou= rce/timer-econet-en751221.c index 4008076b1a21..e280ee8c2b1c 100644 --- a/drivers/clocksource/timer-econet-en751221.c +++ b/drivers/clocksource/timer-econet-en751221.c @@ -3,11 +3,13 @@ * Timer present on EcoNet EN75xx MIPS based SoCs. * * Copyright (C) 2025 by Caleb James DeLisle + * Copyright (C) 2025 by Ahmed Naseef */ =20 #include #include #include +#include #include #include #include @@ -21,14 +23,26 @@ #define ECONET_MAX_DELTA GENMASK(ECONET_BITS - 2, 0) /* 34Kc hardware has 1 block and 1004Kc has 2. */ #define ECONET_NUM_BLOCKS DIV_ROUND_UP(NR_CPUS, 2) +#define ECONET_MAX_IRQS NR_CPUS =20 static struct { void __iomem *membase[ECONET_NUM_BLOCKS]; u32 freq_hz; + int irqs[ECONET_MAX_IRQS]; + int num_irqs; } econet_timer __ro_after_init; =20 static DEFINE_PER_CPU(struct clock_event_device, econet_timer_pcpu); =20 +/* This timer supports two interrupt controller models, either 1 IRQ which= is in per-cpu + * mode which is used on 34Kc CPUs, and separate IRQ number per CPU which = is used on + * 1004Kc CPUs with GIC intc. + */ +static inline bool is_percpu_irq(void) +{ + return econet_timer.num_irqs =3D=3D 1; +} + /* Each memory block has 2 timers, the order of registers is: * CTL, CMR0, CNT0, CMR1, CNT1 */ @@ -98,12 +112,21 @@ static int cevt_init_cpu(uint cpu) struct clock_event_device *cd =3D &per_cpu(econet_timer_pcpu, cpu); u32 reg; =20 + if (!is_percpu_irq() && cpu >=3D econet_timer.num_irqs) + return -EINVAL; + pr_debug("%s: Setting up clockevent for CPU %d\n", cd->name, cpu); =20 reg =3D ioread32(reg_ctl(cpu)) | ctl_bit_enabled(cpu); iowrite32(reg, reg_ctl(cpu)); =20 - enable_percpu_irq(cd->irq, IRQ_TYPE_NONE); + if (is_percpu_irq()) { + enable_percpu_irq(cd->irq, IRQ_TYPE_NONE); + } else { + if (irq_force_affinity(econet_timer.irqs[cpu], cpumask_of(cpu))) + pr_warn("%s: failed to set IRQ %d affinity to CPU %d\n", + cd->name, econet_timer.irqs[cpu], cpu); + } =20 /* Do this last because it synchronously configures the timer */ clockevents_config_and_register(cd, econet_timer.freq_hz, @@ -126,7 +149,20 @@ static void __init cevt_dev_init(uint cpu) iowrite32(U32_MAX, reg_compare(cpu)); } =20 -static int __init cevt_init(struct device_node *np) +static void __init cevt_setup_clockevent(struct clock_event_device *cd, + struct device_node *np, + int irq, int cpu) +{ + cd->rating =3D 310; + cd->features =3D CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_C3STOP; + cd->set_next_event =3D cevt_set_next_event; + cd->irq =3D irq; + cd->cpumask =3D cpumask_of(cpu); + cd->name =3D np->name; +} + +static int __init cevt_init_percpu(struct device_node *np) { int i, irq, ret; =20 @@ -137,42 +173,65 @@ static int __init cevt_init(struct device_node *np) } =20 ret =3D request_percpu_irq(irq, cevt_interrupt, np->name, &econet_timer_p= cpu); - if (ret < 0) { pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, irq, ret); - goto err_unmap_irq; + irq_dispose_mapping(irq); + return ret; } =20 for_each_possible_cpu(i) { struct clock_event_device *cd =3D &per_cpu(econet_timer_pcpu, i); =20 - cd->rating =3D 310; - cd->features =3D CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_C3STOP | - CLOCK_EVT_FEAT_PERCPU; - cd->set_next_event =3D cevt_set_next_event; - cd->irq =3D irq; - cd->cpumask =3D cpumask_of(i); - cd->name =3D np->name; + cevt_setup_clockevent(cd, np, irq, i); + cd->features |=3D CLOCK_EVT_FEAT_PERCPU; + cevt_dev_init(i); + } + + return 0; +} =20 +static int __init cevt_init_separate(struct device_node *np) +{ + int i, ret; + + for (i =3D 0; i < econet_timer.num_irqs; i++) { + struct clock_event_device *cd =3D &per_cpu(econet_timer_pcpu, i); + + econet_timer.irqs[i] =3D irq_of_parse_and_map(np, i); + if (econet_timer.irqs[i] <=3D 0) { + pr_err("%pOFn: irq_of_parse_and_map failed", np); + ret =3D -EINVAL; + goto err_free_irqs; + } + + ret =3D request_irq(econet_timer.irqs[i], cevt_interrupt, + IRQF_TIMER | IRQF_NOBALANCING, + np->name, NULL); + if (ret < 0) { + pr_err("%pOFn: IRQ %d setup failed (%d)\n", np, + econet_timer.irqs[i], ret); + irq_dispose_mapping(econet_timer.irqs[i]); + goto err_free_irqs; + } + + cevt_setup_clockevent(cd, np, econet_timer.irqs[i], i); cevt_dev_init(i); } =20 - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, - "clockevents/econet/timer:starting", - cevt_init_cpu, NULL); return 0; =20 -err_unmap_irq: - irq_dispose_mapping(irq); +err_free_irqs: + while (--i >=3D 0) { + free_irq(econet_timer.irqs[i], NULL); + irq_dispose_mapping(econet_timer.irqs[i]); + } return ret; } =20 static int __init timer_init(struct device_node *np) { - int num_blocks =3D DIV_ROUND_UP(num_possible_cpus(), 2); struct clk *clk; - int ret; + int ret, i; =20 clk =3D of_clk_get(np, 0); if (IS_ERR(clk)) { @@ -182,11 +241,18 @@ static int __init timer_init(struct device_node *np) =20 econet_timer.freq_hz =3D clk_get_rate(clk); =20 - for (int i =3D 0; i < num_blocks; i++) { + econet_timer.num_irqs =3D of_irq_count(np); + if (econet_timer.num_irqs <=3D 0 || econet_timer.num_irqs > ECONET_MAX_IR= QS) { + pr_err("%pOFn: invalid IRQ count %d\n", np, econet_timer.num_irqs); + return -EINVAL; + } + + for (i =3D 0; i < ECONET_NUM_BLOCKS; i++) { econet_timer.membase[i] =3D of_iomap(np, i); if (!econet_timer.membase[i]) { pr_err("%pOFn: failed to map register [%d]\n", np, i); - return -ENXIO; + ret =3D -ENXIO; + goto err_unmap; } } =20 @@ -196,21 +262,38 @@ static int __init timer_init(struct device_node *np) clocksource_mmio_readl_up); if (ret) { pr_err("%pOFn: clocksource_mmio_init failed: %d", np, ret); - return ret; + goto err_unmap; } =20 - ret =3D cevt_init(np); + if (is_percpu_irq()) + ret =3D cevt_init_percpu(np); + else + ret =3D cevt_init_separate(np); + if (ret < 0) - return ret; + goto err_unmap; + + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "clockevents/econet/timer:starting", + cevt_init_cpu, NULL); =20 sched_clock_register(sched_clock_read, ECONET_BITS, econet_timer.freq_hz); =20 - pr_info("%pOFn: using %u.%03u MHz high precision timer\n", np, + pr_info("%pOFn: using %u.%03u MHz high precision timer (%s mode)\n", np, econet_timer.freq_hz / 1000000, - (econet_timer.freq_hz / 1000) % 1000); + (econet_timer.freq_hz / 1000) % 1000, + is_percpu_irq() ? "percpu" : "separate IRQ"); =20 return 0; + +err_unmap: + for (i =3D 0; i < ECONET_NUM_BLOCKS; i++) { + if (econet_timer.membase[i]) + iounmap(econet_timer.membase[i]); + } + + return ret; } =20 -TIMER_OF_DECLARE(econet_timer_hpt, "econet,en751221-timer", timer_init); +TIMER_OF_DECLARE(econet_en751221_timer, "econet,en751221-timer", timer_ini= t); --=20 2.39.5