aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBai Ping <ping.bai@nxp.com>2019-06-05 02:40:52 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2019-06-25 13:49:18 -0400
commit7117a44bc0eb5d73dc8aa8df92134f736c2099ac (patch)
tree210e103771226a44126aa4f9b7969ebe1da96a28
parent668f870f98ac935a550e8f9b1fa6ef74831b3b40 (diff)
clocksource/drivers/sysctr: Add nxp system counter timer driver support
The system counter (sys_ctr) is a programmable system counter which provides a shared time base to the Cortex A15, A7, A53 etc cores. It is intended for use in applications where the counter is always powered on and supports multiple, unrelated clocks. The sys_ctr hardware supports: - 56-bit counter width (roll-over time greater than 40 years) - compare frame(64-bit compare value) contains programmable interrupt generation when compare value <= counter value. [dlezcano] Fixed over 80 chars length warning Signed-off-by: Bai Ping <ping.bai@nxp.com> Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/timer/nxp,sysctr-timer.txt25
-rw-r--r--drivers/clocksource/Kconfig7
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/timer-imx-sysctr.c145
4 files changed, 178 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.txt b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.txt
new file mode 100644
index 000000000000..d57659996d62
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/nxp,sysctr-timer.txt
@@ -0,0 +1,25 @@
1NXP System Counter Module(sys_ctr)
2
3The system counter(sys_ctr) is a programmable system counter which provides
4a shared time base to Cortex A15, A7, A53, A73, etc. it is intended for use in
5applications where the counter is always powered and support multiple,
6unrelated clocks. The compare frame inside can be used for timer purpose.
7
8Required properties:
9
10- compatible : should be "nxp,sysctr-timer"
11- reg : Specifies the base physical address and size of the comapre
12 frame and the counter control, read & compare.
13- interrupts : should be the first compare frames' interrupt
14- clocks : Specifies the counter clock.
15- clock-names: Specifies the clock's name of this module
16
17Example:
18
19 system_counter: timer@306a0000 {
20 compatible = "nxp,sysctr-timer";
21 reg = <0x306a0000 0x20000>;/* system-counter-rd & compare */
22 clocks = <&clk_8m>;
23 clock-names = "per";
24 interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
25 };
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d17a347e813a..e9936992934a 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -617,6 +617,13 @@ config CLKSRC_IMX_TPM
617 Enable this option to use IMX Timer/PWM Module (TPM) timer as 617 Enable this option to use IMX Timer/PWM Module (TPM) timer as
618 clocksource. 618 clocksource.
619 619
620config TIMER_IMX_SYS_CTR
621 bool "i.MX system counter timer" if COMPILE_TEST
622 select TIMER_OF
623 help
624 Enable this option to use i.MX system counter timer as a
625 clockevent.
626
620config CLKSRC_ST_LPC 627config CLKSRC_ST_LPC
621 bool "Low power clocksource found in the LPC" if COMPILE_TEST 628 bool "Low power clocksource found in the LPC" if COMPILE_TEST
622 select TIMER_OF if OF 629 select TIMER_OF if OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 4145b21eaed3..0939886b305f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
74obj-$(CONFIG_CLKSRC_TANGO_XTAL) += timer-tango-xtal.o 74obj-$(CONFIG_CLKSRC_TANGO_XTAL) += timer-tango-xtal.o
75obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o 75obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
76obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o 76obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o
77obj-$(CONFIG_TIMER_IMX_SYS_CTR) += timer-imx-sysctr.o
77obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o 78obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
78obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o 79obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
79obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o 80obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
diff --git a/drivers/clocksource/timer-imx-sysctr.c b/drivers/clocksource/timer-imx-sysctr.c
new file mode 100644
index 000000000000..fd7d68066efb
--- /dev/null
+++ b/drivers/clocksource/timer-imx-sysctr.c
@@ -0,0 +1,145 @@
1// SPDX-License-Identifier: GPL-2.0+
2//
3// Copyright 2017-2019 NXP
4
5#include <linux/interrupt.h>
6#include <linux/clockchips.h>
7#include <linux/of_address.h>
8#include <linux/of_irq.h>
9
10#include "timer-of.h"
11
12#define CMP_OFFSET 0x10000
13
14#define CNTCV_LO 0x8
15#define CNTCV_HI 0xc
16#define CMPCV_LO (CMP_OFFSET + 0x20)
17#define CMPCV_HI (CMP_OFFSET + 0x24)
18#define CMPCR (CMP_OFFSET + 0x2c)
19
20#define SYS_CTR_EN 0x1
21#define SYS_CTR_IRQ_MASK 0x2
22
23static void __iomem *sys_ctr_base;
24static u32 cmpcr;
25
26static void sysctr_timer_enable(bool enable)
27{
28 writel(enable ? cmpcr | SYS_CTR_EN : cmpcr, sys_ctr_base + CMPCR);
29}
30
31static void sysctr_irq_acknowledge(void)
32{
33 /*
34 * clear the enable bit(EN =0) will clear
35 * the status bit(ISTAT = 0), then the interrupt
36 * signal will be negated(acknowledged).
37 */
38 sysctr_timer_enable(false);
39}
40
41static inline u64 sysctr_read_counter(void)
42{
43 u32 cnt_hi, tmp_hi, cnt_lo;
44
45 do {
46 cnt_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
47 cnt_lo = readl_relaxed(sys_ctr_base + CNTCV_LO);
48 tmp_hi = readl_relaxed(sys_ctr_base + CNTCV_HI);
49 } while (tmp_hi != cnt_hi);
50
51 return ((u64) cnt_hi << 32) | cnt_lo;
52}
53
54static int sysctr_set_next_event(unsigned long delta,
55 struct clock_event_device *evt)
56{
57 u32 cmp_hi, cmp_lo;
58 u64 next;
59
60 sysctr_timer_enable(false);
61
62 next = sysctr_read_counter();
63
64 next += delta;
65
66 cmp_hi = (next >> 32) & 0x00fffff;
67 cmp_lo = next & 0xffffffff;
68
69 writel_relaxed(cmp_hi, sys_ctr_base + CMPCV_HI);
70 writel_relaxed(cmp_lo, sys_ctr_base + CMPCV_LO);
71
72 sysctr_timer_enable(true);
73
74 return 0;
75}
76
77static int sysctr_set_state_oneshot(struct clock_event_device *evt)
78{
79 return 0;
80}
81
82static int sysctr_set_state_shutdown(struct clock_event_device *evt)
83{
84 sysctr_timer_enable(false);
85
86 return 0;
87}
88
89static irqreturn_t sysctr_timer_interrupt(int irq, void *dev_id)
90{
91 struct clock_event_device *evt = dev_id;
92
93 sysctr_irq_acknowledge();
94
95 evt->event_handler(evt);
96
97 return IRQ_HANDLED;
98}
99
100static struct timer_of to_sysctr = {
101 .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
102 .clkevt = {
103 .name = "i.MX system counter timer",
104 .features = CLOCK_EVT_FEAT_ONESHOT |
105 CLOCK_EVT_FEAT_DYNIRQ,
106 .set_state_oneshot = sysctr_set_state_oneshot,
107 .set_next_event = sysctr_set_next_event,
108 .set_state_shutdown = sysctr_set_state_shutdown,
109 .rating = 200,
110 },
111 .of_irq = {
112 .handler = sysctr_timer_interrupt,
113 .flags = IRQF_TIMER | IRQF_IRQPOLL,
114 },
115 .of_clk = {
116 .name = "per",
117 },
118};
119
120static void __init sysctr_clockevent_init(void)
121{
122 to_sysctr.clkevt.cpumask = cpumask_of(0);
123
124 clockevents_config_and_register(&to_sysctr.clkevt,
125 timer_of_rate(&to_sysctr),
126 0xff, 0x7fffffff);
127}
128
129static int __init sysctr_timer_init(struct device_node *np)
130{
131 int ret = 0;
132
133 ret = timer_of_init(np, &to_sysctr);
134 if (ret)
135 return ret;
136
137 sys_ctr_base = timer_of_base(&to_sysctr);
138 cmpcr = readl(sys_ctr_base + CMPCR);
139 cmpcr &= ~SYS_CTR_EN;
140
141 sysctr_clockevent_init();
142
143 return 0;
144}
145TIMER_OF_DECLARE(sysctr_timer, "nxp,sysctr-timer", sysctr_timer_init);