--- /dev/null
+From 57cbfd333c9d65bfab1a06b49c75536ee28dc2ce Mon Sep 17 00:00:00 2001
+From: Sergio Paracuellos <sergio.paracuellos@gmail.com>
+Date: Mon, 28 Oct 2024 21:36:43 +0100
+Subject: clocksource/drivers/ralink: Add Ralink System Tick Counter driver
+
+System Tick Counter is present on Ralink SoCs RT3352 and MT7620. This
+driver has been in 'arch/mips/ralink' directory since the beggining of
+Ralink architecture support. However, it can be moved into a more proper
+place in 'drivers/clocksource'. Hence add it here adding also support for
+compile test targets and reducing LOC in architecture code folder.
+
+Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
+Link: https://lore.kernel.org/r/20241028203643.191268-2-sergio.paracuellos@gmail.com
+Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
+---
+ arch/mips/ralink/Kconfig | 7 --
+ arch/mips/ralink/Makefile | 2 -
+ arch/mips/ralink/cevt-rt3352.c | 153 -------------------------------------
+ drivers/clocksource/Kconfig | 9 +++
+ drivers/clocksource/Makefile | 1 +
+ drivers/clocksource/timer-ralink.c | 150 ++++++++++++++++++++++++++++++++++++
+ 6 files changed, 160 insertions(+), 162 deletions(-)
+ delete mode 100644 arch/mips/ralink/cevt-rt3352.c
+ create mode 100644 drivers/clocksource/timer-ralink.c
+
+--- a/arch/mips/ralink/Kconfig
++++ b/arch/mips/ralink/Kconfig
+@@ -1,13 +1,6 @@
+ # SPDX-License-Identifier: GPL-2.0
+ if RALINK
+
+-config CLKEVT_RT3352
+- bool
+- depends on SOC_RT305X || SOC_MT7620
+- default y
+- select TIMER_OF
+- select CLKSRC_MMIO
+-
+ config RALINK_ILL_ACC
+ bool
+ depends on SOC_RT305X
+--- a/arch/mips/ralink/Makefile
++++ b/arch/mips/ralink/Makefile
+@@ -10,8 +10,6 @@ ifndef CONFIG_MIPS_GIC
+ obj-y += clk.o timer.o
+ endif
+
+-obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o
+-
+ obj-$(CONFIG_RALINK_ILL_ACC) += ill_acc.o
+
+ obj-$(CONFIG_IRQ_INTC) += irq.o
+--- a/arch/mips/ralink/cevt-rt3352.c
++++ /dev/null
+@@ -1,153 +0,0 @@
+-/*
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License. See the file "COPYING" in the main directory of this archive
+- * for more details.
+- *
+- * Copyright (C) 2013 by John Crispin <john@phrozen.org>
+- */
+-
+-#include <linux/clockchips.h>
+-#include <linux/clocksource.h>
+-#include <linux/interrupt.h>
+-#include <linux/reset.h>
+-#include <linux/init.h>
+-#include <linux/time.h>
+-#include <linux/of.h>
+-#include <linux/of_irq.h>
+-#include <linux/of_address.h>
+-
+-#include <asm/mach-ralink/ralink_regs.h>
+-
+-#define SYSTICK_FREQ (50 * 1000)
+-
+-#define SYSTICK_CONFIG 0x00
+-#define SYSTICK_COMPARE 0x04
+-#define SYSTICK_COUNT 0x08
+-
+-/* route systick irq to mips irq 7 instead of the r4k-timer */
+-#define CFG_EXT_STK_EN 0x2
+-/* enable the counter */
+-#define CFG_CNT_EN 0x1
+-
+-struct systick_device {
+- void __iomem *membase;
+- struct clock_event_device dev;
+- int irq_requested;
+- int freq_scale;
+-};
+-
+-static int systick_set_oneshot(struct clock_event_device *evt);
+-static int systick_shutdown(struct clock_event_device *evt);
+-
+-static int systick_next_event(unsigned long delta,
+- struct clock_event_device *evt)
+-{
+- struct systick_device *sdev;
+- u32 count;
+-
+- sdev = container_of(evt, struct systick_device, dev);
+- count = ioread32(sdev->membase + SYSTICK_COUNT);
+- count = (count + delta) % SYSTICK_FREQ;
+- iowrite32(count, sdev->membase + SYSTICK_COMPARE);
+-
+- return 0;
+-}
+-
+-static void systick_event_handler(struct clock_event_device *dev)
+-{
+- /* noting to do here */
+-}
+-
+-static irqreturn_t systick_interrupt(int irq, void *dev_id)
+-{
+- struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+-
+- dev->event_handler(dev);
+-
+- return IRQ_HANDLED;
+-}
+-
+-static struct systick_device systick = {
+- .dev = {
+- /*
+- * cevt-r4k uses 300, make sure systick
+- * gets used if available
+- */
+- .rating = 310,
+- .features = CLOCK_EVT_FEAT_ONESHOT,
+- .set_next_event = systick_next_event,
+- .set_state_shutdown = systick_shutdown,
+- .set_state_oneshot = systick_set_oneshot,
+- .event_handler = systick_event_handler,
+- },
+-};
+-
+-static int systick_shutdown(struct clock_event_device *evt)
+-{
+- struct systick_device *sdev;
+-
+- sdev = container_of(evt, struct systick_device, dev);
+-
+- if (sdev->irq_requested)
+- free_irq(systick.dev.irq, &systick.dev);
+- sdev->irq_requested = 0;
+- iowrite32(0, systick.membase + SYSTICK_CONFIG);
+-
+- return 0;
+-}
+-
+-static int systick_set_oneshot(struct clock_event_device *evt)
+-{
+- const char *name = systick.dev.name;
+- struct systick_device *sdev;
+- int irq = systick.dev.irq;
+-
+- sdev = container_of(evt, struct systick_device, dev);
+-
+- if (!sdev->irq_requested) {
+- if (request_irq(irq, systick_interrupt,
+- IRQF_PERCPU | IRQF_TIMER, name, &systick.dev))
+- pr_err("Failed to request irq %d (%s)\n", irq, name);
+- }
+- sdev->irq_requested = 1;
+- iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
+- systick.membase + SYSTICK_CONFIG);
+-
+- return 0;
+-}
+-
+-static int __init ralink_systick_init(struct device_node *np)
+-{
+- int ret;
+-
+- systick.membase = of_iomap(np, 0);
+- if (!systick.membase)
+- return -ENXIO;
+-
+- systick.dev.name = np->name;
+- clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
+- systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+- systick.dev.max_delta_ticks = 0x7fff;
+- systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+- systick.dev.min_delta_ticks = 0x3;
+- systick.dev.irq = irq_of_parse_and_map(np, 0);
+- if (!systick.dev.irq) {
+- pr_err("%pOFn: request_irq failed", np);
+- return -EINVAL;
+- }
+-
+- ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+- SYSTICK_FREQ, 301, 16,
+- clocksource_mmio_readl_up);
+- if (ret)
+- return ret;
+-
+- clockevents_register_device(&systick.dev);
+-
+- pr_info("%pOFn: running - mult: %d, shift: %d\n",
+- np, systick.dev.mult, systick.dev.shift);
+-
+- return 0;
+-}
+-
+-TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
+--- a/drivers/clocksource/Kconfig
++++ b/drivers/clocksource/Kconfig
+@@ -732,4 +732,13 @@ config GOLDFISH_TIMER
+ help
+ Support for the timer/counter of goldfish-rtc
+
++config RALINK_TIMER
++ bool "Ralink System Tick Counter"
++ depends on SOC_RT305X || SOC_MT7620 || COMPILE_TEST
++ select CLKSRC_MMIO
++ select TIMER_OF
++ help
++ Enables support for system tick counter present on
++ Ralink SoCs RT3352 and MT7620.
++
+ endmenu
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -89,3 +89,4 @@ obj-$(CONFIG_MSC313E_TIMER) += timer-ms
+ obj-$(CONFIG_GOLDFISH_TIMER) += timer-goldfish.o
+ obj-$(CONFIG_GXP_TIMER) += timer-gxp.o
+ obj-$(CONFIG_CLKSRC_LOONGSON1_PWM) += timer-loongson1-pwm.o
++obj-$(CONFIG_RALINK_TIMER) += timer-ralink.o
+--- /dev/null
++++ b/drivers/clocksource/timer-ralink.c
+@@ -0,0 +1,150 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Ralink System Tick Counter driver present on RT3352 and MT7620 SoCs.
++ *
++ * Copyright (C) 2013 by John Crispin <john@phrozen.org>
++ */
++
++#include <linux/clockchips.h>
++#include <linux/clocksource.h>
++#include <linux/interrupt.h>
++#include <linux/reset.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++
++#define SYSTICK_FREQ (50 * 1000)
++
++#define SYSTICK_CONFIG 0x00
++#define SYSTICK_COMPARE 0x04
++#define SYSTICK_COUNT 0x08
++
++/* route systick irq to mips irq 7 instead of the r4k-timer */
++#define CFG_EXT_STK_EN 0x2
++/* enable the counter */
++#define CFG_CNT_EN 0x1
++
++struct systick_device {
++ void __iomem *membase;
++ struct clock_event_device dev;
++ int irq_requested;
++ int freq_scale;
++};
++
++static int systick_set_oneshot(struct clock_event_device *evt);
++static int systick_shutdown(struct clock_event_device *evt);
++
++static int systick_next_event(unsigned long delta,
++ struct clock_event_device *evt)
++{
++ struct systick_device *sdev;
++ u32 count;
++
++ sdev = container_of(evt, struct systick_device, dev);
++ count = ioread32(sdev->membase + SYSTICK_COUNT);
++ count = (count + delta) % SYSTICK_FREQ;
++ iowrite32(count, sdev->membase + SYSTICK_COMPARE);
++
++ return 0;
++}
++
++static void systick_event_handler(struct clock_event_device *dev)
++{
++ /* noting to do here */
++}
++
++static irqreturn_t systick_interrupt(int irq, void *dev_id)
++{
++ struct clock_event_device *dev = (struct clock_event_device *)dev_id;
++
++ dev->event_handler(dev);
++
++ return IRQ_HANDLED;
++}
++
++static struct systick_device systick = {
++ .dev = {
++ /*
++ * cevt-r4k uses 300, make sure systick
++ * gets used if available
++ */
++ .rating = 310,
++ .features = CLOCK_EVT_FEAT_ONESHOT,
++ .set_next_event = systick_next_event,
++ .set_state_shutdown = systick_shutdown,
++ .set_state_oneshot = systick_set_oneshot,
++ .event_handler = systick_event_handler,
++ },
++};
++
++static int systick_shutdown(struct clock_event_device *evt)
++{
++ struct systick_device *sdev;
++
++ sdev = container_of(evt, struct systick_device, dev);
++
++ if (sdev->irq_requested)
++ free_irq(systick.dev.irq, &systick.dev);
++ sdev->irq_requested = 0;
++ iowrite32(0, systick.membase + SYSTICK_CONFIG);
++
++ return 0;
++}
++
++static int systick_set_oneshot(struct clock_event_device *evt)
++{
++ const char *name = systick.dev.name;
++ struct systick_device *sdev;
++ int irq = systick.dev.irq;
++
++ sdev = container_of(evt, struct systick_device, dev);
++
++ if (!sdev->irq_requested) {
++ if (request_irq(irq, systick_interrupt,
++ IRQF_PERCPU | IRQF_TIMER, name, &systick.dev))
++ pr_err("Failed to request irq %d (%s)\n", irq, name);
++ }
++ sdev->irq_requested = 1;
++ iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
++ systick.membase + SYSTICK_CONFIG);
++
++ return 0;
++}
++
++static int __init ralink_systick_init(struct device_node *np)
++{
++ int ret;
++
++ systick.membase = of_iomap(np, 0);
++ if (!systick.membase)
++ return -ENXIO;
++
++ systick.dev.name = np->name;
++ clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
++ systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
++ systick.dev.max_delta_ticks = 0x7fff;
++ systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
++ systick.dev.min_delta_ticks = 0x3;
++ systick.dev.irq = irq_of_parse_and_map(np, 0);
++ if (!systick.dev.irq) {
++ pr_err("%pOFn: request_irq failed", np);
++ return -EINVAL;
++ }
++
++ ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
++ SYSTICK_FREQ, 301, 16,
++ clocksource_mmio_readl_up);
++ if (ret)
++ return ret;
++
++ clockevents_register_device(&systick.dev);
++
++ pr_info("%pOFn: running - mult: %d, shift: %d\n",
++ np, systick.dev.mult, systick.dev.shift);
++
++ return 0;
++}
++
++TIMER_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
-From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 16:26:41 +0200
-Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
+Subject: [PATCH 2/2] MIPS: ralink: add cpu frequency scaling
This feature will break udelay() and cause the delay loop to have longer delays
when the frequency is scaled causing a performance hit.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
- arch/mips/ralink/cevt-rt3352.c | 38 ++++++++++++++++++++++++++++++++++++++
- 1 file changed, 38 insertions(+)
+ drivers/clocksource/timer-ralink.c | 117 ++++++++++++++++++++++-------
+ 1 file changed, 89 insertions(+), 28 deletions(-)
---- a/arch/mips/ralink/cevt-rt3352.c
-+++ b/arch/mips/ralink/cevt-rt3352.c
-@@ -29,6 +29,10 @@
+--- a/drivers/clocksource/timer-ralink.c
++++ b/drivers/clocksource/timer-ralink.c
+@@ -5,6 +5,7 @@
+ * Copyright (C) 2013 by John Crispin <john@phrozen.org>
+ */
+
++#include <asm/mach-ralink/ralink_regs.h>
+ #include <linux/clockchips.h>
+ #include <linux/clocksource.h>
+ #include <linux/interrupt.h>
+@@ -26,6 +27,10 @@
/* enable the counter */
#define CFG_CNT_EN 0x1
struct systick_device {
void __iomem *membase;
struct clock_event_device dev;
-@@ -36,21 +40,53 @@ struct systick_device {
+@@ -33,21 +38,53 @@ struct systick_device {
int freq_scale;
};
+}
+
static int systick_next_event(unsigned long delta,
- struct clock_event_device *evt)
+ struct clock_event_device *evt)
{
struct systick_device *sdev;
- u32 count;
}
static void systick_event_handler(struct clock_event_device *dev)
-@@ -60,20 +96,25 @@ static void systick_event_handler(struct
+@@ -57,20 +94,25 @@ static void systick_event_handler(struct
static irqreturn_t systick_interrupt(int irq, void *dev_id)
{
-- struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+- struct clock_event_device *dev = (struct clock_event_device *)dev_id;
+ int ret = 0;
+ struct clock_event_device *cdev;
+ struct systick_device *sdev;
- dev->event_handler(dev);
+ if (read_c0_cause() & STATUSF_IP7) {
-+ cdev = (struct clock_event_device *) dev_id;
++ cdev = (struct clock_event_device *)dev_id;
+ sdev = container_of(cdev, struct systick_device, dev);
+
+ /* Clear Count/Compare Interrupt */
.features = CLOCK_EVT_FEAT_ONESHOT,
.set_next_event = systick_next_event,
.set_state_shutdown = systick_shutdown,
-@@ -91,7 +132,13 @@ static int systick_shutdown(struct clock
+@@ -88,7 +130,13 @@ static int systick_shutdown(struct clock
if (sdev->irq_requested)
free_irq(systick.dev.irq, &systick.dev);
sdev->irq_requested = 0;
return 0;
}
-@@ -116,33 +163,46 @@ static int systick_set_oneshot(struct cl
+@@ -113,33 +161,46 @@ static int systick_set_oneshot(struct cl
return 0;
}