aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-11-04 11:15:15 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-11-04 11:15:15 -0500
commit35e7452442687d7bd70f042ddfa92f89311b039c (patch)
tree01c5c4005da691dbf1c53ce1fb1dfee51f6b6301
parent04578e8441c5420259a71eff9fede535858bfc6a (diff)
parentbff9a1076adfb787036ced707fc28cfa578aee99 (diff)
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull more timer updates from Thomas Gleixner: "A set of commits for the new C-SKY architecture timers" * 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: dt-bindings: timer: gx6605s SOC timer clocksource/drivers/c-sky: Add gx6605s SOC system timer dt-bindings: timer: C-SKY Multi-processor timer clocksource/drivers/c-sky: Add C-SKY SMP timer
-rw-r--r--Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt42
-rw-r--r--Documentation/devicetree/bindings/timer/csky,mptimer.txt42
-rw-r--r--drivers/clocksource/Kconfig18
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/timer-gx6605s.c154
-rw-r--r--drivers/clocksource/timer-mp-csky.c173
-rw-r--r--include/linux/cpuhotplug.h1
7 files changed, 432 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt b/Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt
new file mode 100644
index 000000000000..6b04344f4bea
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/csky,gx6605s-timer.txt
@@ -0,0 +1,42 @@
1=================
2gx6605s SOC Timer
3=================
4
5The timer is used in gx6605s soc as system timer and the driver
6contain clk event and clk source.
7
8==============================
9timer node bindings definition
10==============================
11
12 Description: Describes gx6605s SOC timer
13
14 PROPERTIES
15
16 - compatible
17 Usage: required
18 Value type: <string>
19 Definition: must be "csky,gx6605s-timer"
20 - reg
21 Usage: required
22 Value type: <u32 u32>
23 Definition: <phyaddr size> in soc from cpu view
24 - clocks
25 Usage: required
26 Value type: phandle + clock specifier cells
27 Definition: must be input clk node
28 - interrupt
29 Usage: required
30 Value type: <u32>
31 Definition: must be timer irq num defined by soc
32
33Examples:
34---------
35
36 timer0: timer@20a000 {
37 compatible = "csky,gx6605s-timer";
38 reg = <0x0020a000 0x400>;
39 clocks = <&dummy_apb_clk>;
40 interrupts = <10>;
41 interrupt-parent = <&intc>;
42 };
diff --git a/Documentation/devicetree/bindings/timer/csky,mptimer.txt b/Documentation/devicetree/bindings/timer/csky,mptimer.txt
new file mode 100644
index 000000000000..15cfec08fbb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/csky,mptimer.txt
@@ -0,0 +1,42 @@
1============================
2C-SKY Multi-processors Timer
3============================
4
5C-SKY multi-processors timer is designed for C-SKY SMP system and the
6regs is accessed by cpu co-processor 4 registers with mtcr/mfcr.
7
8 - PTIM_CTLR "cr<0, 14>" Control reg to start reset timer.
9 - PTIM_TSR "cr<1, 14>" Interrupt cleanup status reg.
10 - PTIM_CCVR "cr<3, 14>" Current counter value reg.
11 - PTIM_LVR "cr<6, 14>" Window value reg to triger next event.
12
13==============================
14timer node bindings definition
15==============================
16
17 Description: Describes SMP timer
18
19 PROPERTIES
20
21 - compatible
22 Usage: required
23 Value type: <string>
24 Definition: must be "csky,mptimer"
25 - clocks
26 Usage: required
27 Value type: <node>
28 Definition: must be input clk node
29 - interrupts
30 Usage: required
31 Value type: <u32>
32 Definition: must be timer irq num defined by soc
33
34Examples:
35---------
36
37 timer: timer {
38 compatible = "csky,mptimer";
39 clocks = <&dummy_apb_clk>;
40 interrupts = <16>;
41 interrupt-parent = <&intc>;
42 };
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index a11f4ba98b05..55c77e44bb2d 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -620,4 +620,22 @@ config RISCV_TIMER
620 is accessed via both the SBI and the rdcycle instruction. This is 620 is accessed via both the SBI and the rdcycle instruction. This is
621 required for all RISC-V systems. 621 required for all RISC-V systems.
622 622
623config CSKY_MP_TIMER
624 bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
625 depends on CSKY
626 select TIMER_OF
627 help
628 Say yes here to enable C-SKY SMP timer driver used for C-SKY SMP
629 system.
630 csky,mptimer is not only used in SMP system, it also could be used
631 single core system. It's not a mmio reg and it use mtcr/mfcr instruction.
632
633config GX6605S_TIMER
634 bool "Gx6605s SOC system timer driver" if COMPILE_TEST
635 depends on CSKY
636 select CLKSRC_MMIO
637 select TIMER_OF
638 help
639 This option enables support for gx6605s SOC's timer.
640
623endmenu 641endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index e33b21d3f9d8..dd9138104568 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -79,3 +79,5 @@ obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
79obj-$(CONFIG_X86_NUMACHIP) += numachip.o 79obj-$(CONFIG_X86_NUMACHIP) += numachip.o
80obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o 80obj-$(CONFIG_ATCPIT100_TIMER) += timer-atcpit100.o
81obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o 81obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
82obj-$(CONFIG_CSKY_MP_TIMER) += timer-mp-csky.o
83obj-$(CONFIG_GX6605S_TIMER) += timer-gx6605s.o
diff --git a/drivers/clocksource/timer-gx6605s.c b/drivers/clocksource/timer-gx6605s.c
new file mode 100644
index 000000000000..80d0939d040b
--- /dev/null
+++ b/drivers/clocksource/timer-gx6605s.c
@@ -0,0 +1,154 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3
4#include <linux/init.h>
5#include <linux/interrupt.h>
6#include <linux/sched_clock.h>
7
8#include "timer-of.h"
9
10#define CLKSRC_OFFSET 0x40
11
12#define TIMER_STATUS 0x00
13#define TIMER_VALUE 0x04
14#define TIMER_CONTRL 0x10
15#define TIMER_CONFIG 0x20
16#define TIMER_DIV 0x24
17#define TIMER_INI 0x28
18
19#define GX6605S_STATUS_CLR BIT(0)
20#define GX6605S_CONTRL_RST BIT(0)
21#define GX6605S_CONTRL_START BIT(1)
22#define GX6605S_CONFIG_EN BIT(0)
23#define GX6605S_CONFIG_IRQ_EN BIT(1)
24
25static irqreturn_t gx6605s_timer_interrupt(int irq, void *dev)
26{
27 struct clock_event_device *ce = dev;
28 void __iomem *base = timer_of_base(to_timer_of(ce));
29
30 writel_relaxed(GX6605S_STATUS_CLR, base + TIMER_STATUS);
31
32 ce->event_handler(ce);
33
34 return IRQ_HANDLED;
35}
36
37static int gx6605s_timer_set_oneshot(struct clock_event_device *ce)
38{
39 void __iomem *base = timer_of_base(to_timer_of(ce));
40
41 /* reset and stop counter */
42 writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
43
44 /* enable with irq and start */
45 writel_relaxed(GX6605S_CONFIG_EN | GX6605S_CONFIG_IRQ_EN,
46 base + TIMER_CONFIG);
47
48 return 0;
49}
50
51static int gx6605s_timer_set_next_event(unsigned long delta,
52 struct clock_event_device *ce)
53{
54 void __iomem *base = timer_of_base(to_timer_of(ce));
55
56 /* use reset to pause timer */
57 writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
58
59 /* config next timeout value */
60 writel_relaxed(ULONG_MAX - delta, base + TIMER_INI);
61 writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
62
63 return 0;
64}
65
66static int gx6605s_timer_shutdown(struct clock_event_device *ce)
67{
68 void __iomem *base = timer_of_base(to_timer_of(ce));
69
70 writel_relaxed(0, base + TIMER_CONTRL);
71 writel_relaxed(0, base + TIMER_CONFIG);
72
73 return 0;
74}
75
76static struct timer_of to = {
77 .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
78 .clkevt = {
79 .rating = 300,
80 .features = CLOCK_EVT_FEAT_DYNIRQ |
81 CLOCK_EVT_FEAT_ONESHOT,
82 .set_state_shutdown = gx6605s_timer_shutdown,
83 .set_state_oneshot = gx6605s_timer_set_oneshot,
84 .set_next_event = gx6605s_timer_set_next_event,
85 .cpumask = cpu_possible_mask,
86 },
87 .of_irq = {
88 .handler = gx6605s_timer_interrupt,
89 .flags = IRQF_TIMER | IRQF_IRQPOLL,
90 },
91};
92
93static u64 notrace gx6605s_sched_clock_read(void)
94{
95 void __iomem *base;
96
97 base = timer_of_base(&to) + CLKSRC_OFFSET;
98
99 return (u64)readl_relaxed(base + TIMER_VALUE);
100}
101
102static void gx6605s_clkevt_init(void __iomem *base)
103{
104 writel_relaxed(0, base + TIMER_DIV);
105 writel_relaxed(0, base + TIMER_CONFIG);
106
107 clockevents_config_and_register(&to.clkevt, timer_of_rate(&to), 2,
108 ULONG_MAX);
109}
110
111static int gx6605s_clksrc_init(void __iomem *base)
112{
113 writel_relaxed(0, base + TIMER_DIV);
114 writel_relaxed(0, base + TIMER_INI);
115
116 writel_relaxed(GX6605S_CONTRL_RST, base + TIMER_CONTRL);
117
118 writel_relaxed(GX6605S_CONFIG_EN, base + TIMER_CONFIG);
119
120 writel_relaxed(GX6605S_CONTRL_START, base + TIMER_CONTRL);
121
122 sched_clock_register(gx6605s_sched_clock_read, 32, timer_of_rate(&to));
123
124 return clocksource_mmio_init(base + TIMER_VALUE, "gx6605s",
125 timer_of_rate(&to), 200, 32, clocksource_mmio_readl_up);
126}
127
128static int __init gx6605s_timer_init(struct device_node *np)
129{
130 int ret;
131
132 /*
133 * The timer driver is for nationalchip gx6605s SOC and there are two
134 * same timer in gx6605s. We use one for clkevt and another for clksrc.
135 *
136 * The timer is mmio map to access, so we need give mmio address in dts.
137 *
138 * It provides a 32bit countup timer and interrupt will be caused by
139 * count-overflow.
140 * So we need set-next-event by ULONG_MAX - delta in TIMER_INI reg.
141 *
142 * The counter at 0x0 offset is clock event.
143 * The counter at 0x40 offset is clock source.
144 * They are the same in hardware, just different used by driver.
145 */
146 ret = timer_of_init(np, &to);
147 if (ret)
148 return ret;
149
150 gx6605s_clkevt_init(timer_of_base(&to));
151
152 return gx6605s_clksrc_init(timer_of_base(&to) + CLKSRC_OFFSET);
153}
154TIMER_OF_DECLARE(csky_gx6605s_timer, "csky,gx6605s-timer", gx6605s_timer_init);
diff --git a/drivers/clocksource/timer-mp-csky.c b/drivers/clocksource/timer-mp-csky.c
new file mode 100644
index 000000000000..a8acc431a774
--- /dev/null
+++ b/drivers/clocksource/timer-mp-csky.c
@@ -0,0 +1,173 @@
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3
4#include <linux/init.h>
5#include <linux/interrupt.h>
6#include <linux/sched_clock.h>
7#include <linux/cpu.h>
8#include <linux/of_irq.h>
9#include <asm/reg_ops.h>
10
11#include "timer-of.h"
12
13#define PTIM_CCVR "cr<3, 14>"
14#define PTIM_CTLR "cr<0, 14>"
15#define PTIM_LVR "cr<6, 14>"
16#define PTIM_TSR "cr<1, 14>"
17
18static int csky_mptimer_irq;
19
20static int csky_mptimer_set_next_event(unsigned long delta,
21 struct clock_event_device *ce)
22{
23 mtcr(PTIM_LVR, delta);
24
25 return 0;
26}
27
28static int csky_mptimer_shutdown(struct clock_event_device *ce)
29{
30 mtcr(PTIM_CTLR, 0);
31
32 return 0;
33}
34
35static int csky_mptimer_oneshot(struct clock_event_device *ce)
36{
37 mtcr(PTIM_CTLR, 1);
38
39 return 0;
40}
41
42static int csky_mptimer_oneshot_stopped(struct clock_event_device *ce)
43{
44 mtcr(PTIM_CTLR, 0);
45
46 return 0;
47}
48
49static DEFINE_PER_CPU(struct timer_of, csky_to) = {
50 .flags = TIMER_OF_CLOCK,
51 .clkevt = {
52 .rating = 300,
53 .features = CLOCK_EVT_FEAT_PERCPU |
54 CLOCK_EVT_FEAT_ONESHOT,
55 .set_state_shutdown = csky_mptimer_shutdown,
56 .set_state_oneshot = csky_mptimer_oneshot,
57 .set_state_oneshot_stopped = csky_mptimer_oneshot_stopped,
58 .set_next_event = csky_mptimer_set_next_event,
59 },
60};
61
62static irqreturn_t csky_timer_interrupt(int irq, void *dev)
63{
64 struct timer_of *to = this_cpu_ptr(&csky_to);
65
66 mtcr(PTIM_TSR, 0);
67
68 to->clkevt.event_handler(&to->clkevt);
69
70 return IRQ_HANDLED;
71}
72
73/*
74 * clock event for percpu
75 */
76static int csky_mptimer_starting_cpu(unsigned int cpu)
77{
78 struct timer_of *to = per_cpu_ptr(&csky_to, cpu);
79
80 to->clkevt.cpumask = cpumask_of(cpu);
81
82 clockevents_config_and_register(&to->clkevt, timer_of_rate(to),
83 2, ULONG_MAX);
84
85 enable_percpu_irq(csky_mptimer_irq, 0);
86
87 return 0;
88}
89
90static int csky_mptimer_dying_cpu(unsigned int cpu)
91{
92 disable_percpu_irq(csky_mptimer_irq);
93
94 return 0;
95}
96
97/*
98 * clock source
99 */
100static u64 sched_clock_read(void)
101{
102 return (u64)mfcr(PTIM_CCVR);
103}
104
105static u64 clksrc_read(struct clocksource *c)
106{
107 return (u64)mfcr(PTIM_CCVR);
108}
109
110struct clocksource csky_clocksource = {
111 .name = "csky",
112 .rating = 400,
113 .mask = CLOCKSOURCE_MASK(32),
114 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
115 .read = clksrc_read,
116};
117
118static int __init csky_mptimer_init(struct device_node *np)
119{
120 int ret, cpu, cpu_rollback;
121 struct timer_of *to = NULL;
122
123 /*
124 * Csky_mptimer is designed for C-SKY SMP multi-processors and
125 * every core has it's own private irq and regs for clkevt and
126 * clksrc.
127 *
128 * The regs is accessed by cpu instruction: mfcr/mtcr instead of
129 * mmio map style. So we needn't mmio-address in dts, but we still
130 * need to give clk and irq number.
131 *
132 * We use private irq for the mptimer and irq number is the same
133 * for every core. So we use request_percpu_irq() in timer_of_init.
134 */
135 csky_mptimer_irq = irq_of_parse_and_map(np, 0);
136 if (csky_mptimer_irq <= 0)
137 return -EINVAL;
138
139 ret = request_percpu_irq(csky_mptimer_irq, csky_timer_interrupt,
140 "csky_mp_timer", &csky_to);
141 if (ret)
142 return -EINVAL;
143
144 for_each_possible_cpu(cpu) {
145 to = per_cpu_ptr(&csky_to, cpu);
146 ret = timer_of_init(np, to);
147 if (ret)
148 goto rollback;
149 }
150
151 clocksource_register_hz(&csky_clocksource, timer_of_rate(to));
152 sched_clock_register(sched_clock_read, 32, timer_of_rate(to));
153
154 ret = cpuhp_setup_state(CPUHP_AP_CSKY_TIMER_STARTING,
155 "clockevents/csky/timer:starting",
156 csky_mptimer_starting_cpu,
157 csky_mptimer_dying_cpu);
158 if (ret)
159 return -EINVAL;
160
161 return 0;
162
163rollback:
164 for_each_possible_cpu(cpu_rollback) {
165 if (cpu_rollback == cpu)
166 break;
167
168 to = per_cpu_ptr(&csky_to, cpu_rollback);
169 timer_of_cleanup(to);
170 }
171 return -EINVAL;
172}
173TIMER_OF_DECLARE(csky_mptimer, "csky,mptimer", csky_mptimer_init);
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index caf40ad0bbc6..e0cd2baa8380 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -126,6 +126,7 @@ enum cpuhp_state {
126 CPUHP_AP_MIPS_GIC_TIMER_STARTING, 126 CPUHP_AP_MIPS_GIC_TIMER_STARTING,
127 CPUHP_AP_ARC_TIMER_STARTING, 127 CPUHP_AP_ARC_TIMER_STARTING,
128 CPUHP_AP_RISCV_TIMER_STARTING, 128 CPUHP_AP_RISCV_TIMER_STARTING,
129 CPUHP_AP_CSKY_TIMER_STARTING,
129 CPUHP_AP_KVM_STARTING, 130 CPUHP_AP_KVM_STARTING,
130 CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, 131 CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
131 CPUHP_AP_KVM_ARM_VGIC_STARTING, 132 CPUHP_AP_KVM_ARM_VGIC_STARTING,