From: Yasha Cherikovsky <yasha.che3@gmail.com>
To: Ralf Baechle <ralf@linux-mips.org>,
Paul Burton <paul.burton@mips.com>,
James Hogan <jhogan@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
Jason Cooper <jason@lakedaemon.net>,
Marc Zyngier <marc.zyngier@arm.com>,
Daniel Lezcano <daniel.lezcano@linaro.org>,
Rob Herring <robh+dt@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
linux-mips@linux-mips.org, devicetree@vger.kernel.org
Cc: Yasha Cherikovsky <yasha.che3@gmail.com>, linux-kernel@vger.kernel.org
Subject: [RFC v2 5/7] clocksource/drivers/rtl8186: Add RTL8186 timer driver
Date: Mon, 1 Oct 2018 13:29:50 +0300 [thread overview]
Message-ID: <20181001102952.7913-6-yasha.che3@gmail.com> (raw)
In-Reply-To: <20181001102952.7913-1-yasha.che3@gmail.com>
The Realtek RTL8186 SoC is a MIPS based SoC
used in some home routers [1][2].
This adds a driver to handle the built-in timers
on this SoC.
Timers 0 and 1 are 24bit timers.
Timers 2 and 3 are 32bit timers.
Use Timer2 as clocksource and Timer3 for clockevents.
Timer2 is also used for sched_clock.
[1] https://www.linux-mips.org/wiki/Realtek_SOC#Realtek_RTL8186
[2] https://wikidevi.com/wiki/Realtek_RTL8186
Signed-off-by: Yasha Cherikovsky <yasha.che3@gmail.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Paul Burton <paul.burton@mips.com>
Cc: James Hogan <jhogan@kernel.org>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: linux-mips@linux-mips.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
drivers/clocksource/Kconfig | 9 ++
drivers/clocksource/Makefile | 1 +
drivers/clocksource/timer-rtl8186.c | 220 ++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/clocksource/timer-rtl8186.c
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index dec0dd88ec15..da87f73d0631 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -609,4 +609,13 @@ config ATCPIT100_TIMER
help
This option enables support for the Andestech ATCPIT100 timers.
+config RTL8186_TIMER
+ bool "RTL8186 timer driver"
+ depends on MACH_RTL8186
+ depends on COMMON_CLK
+ select TIMER_OF
+ select CLKSRC_MMIO
+ help
+ Enables support for the RTL8186 timer driver.
+
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 00caf37e52f9..734e8566e1b6 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
obj-$(CONFIG_X86_NUMACHIP) += numachip.o
obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
+obj-$(CONFIG_RTL8186_TIMER) += timer-rtl8186.o
diff --git a/drivers/clocksource/timer-rtl8186.c b/drivers/clocksource/timer-rtl8186.c
new file mode 100644
index 000000000000..47ef4b09ad27
--- /dev/null
+++ b/drivers/clocksource/timer-rtl8186.c
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Realtek RTL8186 SoC timer driver.
+ *
+ * Timer0 (24bit): Unused
+ * Timer1 (24bit): Unused
+ * Timer2 (32bit): Used as clocksource
+ * Timer3 (32bit): Used as clock event device
+ *
+ * Copyright (C) 2018 Yasha Cherikovsky
+ */
+
+#include <linux/init.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/sched_clock.h>
+#include <linux/of_clk.h>
+#include <linux/io.h>
+
+#include <asm/time.h>
+#include <asm/idle.h>
+
+#include "timer-of.h"
+
+/* Timer registers */
+#define TCCNR 0x0
+#define TCIR 0x4
+#define TC_DATA(t) (0x10 + 4 * (t))
+#define TC_CNT(t) (0x20 + 4 * (t))
+
+/* TCCNR register bits */
+#define TCCNR_TC_EN_BIT(t) BIT((t) * 2)
+#define TCCNR_TC_MODE_BIT(t) BIT((t) * 2 + 1)
+#define TCCNR_TC_SRC_BIT(t) BIT((t) + 8)
+
+/* TCIR register bits */
+#define TCIR_TC_IE_BIT(t) BIT(t)
+#define TCIR_TC_IP_BIT(t) BIT((t) + 4)
+
+
+/* Forward declaration */
+static struct timer_of to;
+
+static void __iomem *base;
+
+
+#define RTL8186_TIMER_MODE_COUNTER 0
+#define RTL8186_TIMER_MODE_TIMER 1
+
+static void rtl8186_set_enable_bit(int timer, int enabled)
+{
+ u16 tccnr;
+
+ tccnr = readl(base + TCCNR);
+ tccnr &= ~(TCCNR_TC_EN_BIT(timer));
+
+ if (enabled)
+ tccnr |= TCCNR_TC_EN_BIT(timer);
+
+ writel(tccnr, base + TCCNR);
+}
+
+static void rtl8186_set_mode_bit(int timer, int mode)
+{
+ u16 tccnr;
+
+ tccnr = readl(base + TCCNR);
+ tccnr &= ~(TCCNR_TC_MODE_BIT(timer));
+
+ if (mode)
+ tccnr |= TCCNR_TC_MODE_BIT(timer);
+
+ writel(tccnr, base + TCCNR);
+}
+
+
+static irqreturn_t rtl8186_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *cd = dev_id;
+ int status;
+
+ status = readl(base + TCIR);
+ writel(status, base + TCIR); /* Clear all interrupts */
+
+ cd->event_handler(cd);
+
+ return IRQ_HANDLED;
+}
+
+static int rtl8186_clockevent_set_next(unsigned long evt,
+ struct clock_event_device *cd)
+{
+ rtl8186_set_enable_bit(3, 0);
+ writel(evt, base + TC_DATA(3));
+ writel(evt, base + TC_CNT(3));
+ rtl8186_set_enable_bit(3, 1);
+ return 0;
+}
+
+static int rtl8186_set_state_periodic(struct clock_event_device *cd)
+{
+ unsigned long period = timer_of_period(to_timer_of(cd));
+
+ rtl8186_set_enable_bit(3, 0);
+ rtl8186_set_mode_bit(3, RTL8186_TIMER_MODE_TIMER);
+
+ /* This timer should reach zero each jiffy */
+ writel(period, base + TC_DATA(3));
+ writel(period, base + TC_CNT(3));
+
+ rtl8186_set_enable_bit(3, 1);
+ return 0;
+}
+
+static int rtl8186_set_state_oneshot(struct clock_event_device *cd)
+{
+ rtl8186_set_enable_bit(3, 0);
+ rtl8186_set_mode_bit(3, RTL8186_TIMER_MODE_COUNTER);
+ return 0;
+}
+
+static int rtl8186_set_state_shutdown(struct clock_event_device *cd)
+{
+ rtl8186_set_enable_bit(3, 0);
+ return 0;
+}
+
+static void rtl8186_timer_init_hw(void)
+{
+ /* Disable all timers */
+ writel(0, base + TCCNR);
+
+ /* Clear and disable all timer interrupts */
+ writel(0xf0, base + TCIR);
+
+ /* Reset all timers timeouts */
+ writel(0, base + TC_DATA(0));
+ writel(0, base + TC_DATA(1));
+ writel(0, base + TC_DATA(2));
+ writel(0, base + TC_DATA(3));
+
+ /* Reset all counters */
+ writel(0, base + TC_CNT(0));
+ writel(0, base + TC_CNT(1));
+ writel(0, base + TC_CNT(2));
+ writel(0, base + TC_CNT(3));
+}
+
+static u64 notrace rtl8186_timer_sched_read(void)
+{
+ return ~readl(base + TC_CNT(2));
+}
+
+static int rtl8186_start_clksrc(void)
+{
+ /* We use Timer2 as a clocksource (monotonic counter). */
+ writel(0xFFFFFFFF, base + TC_DATA(2));
+ writel(0xFFFFFFFF, base + TC_CNT(2));
+
+ rtl8186_set_mode_bit(2, RTL8186_TIMER_MODE_TIMER);
+ rtl8186_set_enable_bit(2, 1);
+
+ sched_clock_register(rtl8186_timer_sched_read, 32, timer_of_rate(&to));
+
+ return clocksource_mmio_init(base + TC_CNT(2), "rtl8186-clksrc",
+ timer_of_rate(&to), 500, 32,
+ clocksource_mmio_readl_down);
+}
+
+static struct timer_of to = {
+ .flags = TIMER_OF_BASE | TIMER_OF_CLOCK | TIMER_OF_IRQ,
+
+ .clkevt = {
+ .name = "rtl8186_tick",
+ .rating = 200,
+ .features = CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_PERIODIC,
+ .set_next_event = rtl8186_clockevent_set_next,
+ .cpumask = cpu_possible_mask,
+ .set_state_periodic = rtl8186_set_state_periodic,
+ .set_state_oneshot = rtl8186_set_state_oneshot,
+ .set_state_shutdown = rtl8186_set_state_shutdown,
+ },
+
+ .of_irq = {
+ .handler = rtl8186_timer_interrupt,
+ .flags = IRQF_TIMER,
+ },
+};
+
+static int __init rtl8186_timer_init(struct device_node *node)
+{
+ int ret;
+
+ ret = timer_of_init(node, &to);
+ if (ret)
+ return ret;
+
+ base = timer_of_base(&to);
+
+ rtl8186_timer_init_hw();
+
+ ret = rtl8186_start_clksrc();
+ if (ret) {
+ pr_err("Failed to register clocksource\n");
+ return ret;
+ }
+
+ clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 100,
+ 0xffffffff);
+
+ /* Enable interrupts for Timer3. Disable interrupts for others */
+ writel(TCIR_TC_IE_BIT(3), base + TCIR);
+
+ return 0;
+}
+
+TIMER_OF_DECLARE(rtl8186_timer, "realtek,rtl8186-timer", rtl8186_timer_init);
--
2.19.0
next prev parent reply other threads:[~2018-10-01 10:31 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-10-01 10:29 [RFC v2 0/7] MIPS: Lexra LX5280 CPU + Realtek RTL8186 SoC support Yasha Cherikovsky
2018-10-01 10:29 ` [RFC v2 1/7] MIPS: Add support for the Lexra LX5280 CPU Yasha Cherikovsky
2018-11-13 16:33 ` Maciej W. Rozycki
2018-10-01 10:29 ` [RFC v2 2/7] dt-binding: interrupt-controller: Document RTL8186 SoC DT bindings Yasha Cherikovsky
2018-10-12 20:13 ` Rob Herring
2018-10-13 19:42 ` Yasha Cherikovsky
2018-10-01 10:29 ` [RFC v2 3/7] irqchip/rtl8186: Add RTL8186 interrupt controller driver Yasha Cherikovsky
2018-10-01 10:47 ` Marc Zyngier
2018-10-01 10:29 ` [RFC v2 4/7] dt-binding: timer: Document RTL8186 SoC DT bindings Yasha Cherikovsky
2018-10-12 20:14 ` Rob Herring
2018-10-12 20:14 ` Rob Herring
2018-10-12 20:14 ` Rob Herring
2018-10-01 10:29 ` Yasha Cherikovsky [this message]
2018-11-18 1:39 ` [RFC v2 5/7] clocksource/drivers/rtl8186: Add RTL8186 timer driver Daniel Lezcano
2018-10-01 10:29 ` [RFC v2 6/7] dt-binding: mips: Document Realtek SoC DT bindings Yasha Cherikovsky
2018-10-12 20:15 ` Rob Herring
2018-10-12 20:15 ` Rob Herring
2018-10-12 20:15 ` Rob Herring
2018-10-01 10:29 ` [RFC v2 7/7] MIPS: Add Realtek RTL8186 SoC support Yasha Cherikovsky
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=20181001102952.7913-6-yasha.che3@gmail.com \
--to=yasha.che3@gmail.com \
--cc=daniel.lezcano@linaro.org \
--cc=devicetree@vger.kernel.org \
--cc=jason@lakedaemon.net \
--cc=jhogan@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=marc.zyngier@arm.com \
--cc=mark.rutland@arm.com \
--cc=paul.burton@mips.com \
--cc=ralf@linux-mips.org \
--cc=robh+dt@kernel.org \
--cc=tglx@linutronix.de \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.