1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2015 ARM Limited
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Vladimir Murzin <vladimir.murzin@arm.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/clockchips.h>
12*4882a593Smuzhiyun #include <linux/clocksource.h>
13*4882a593Smuzhiyun #include <linux/err.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/io.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/of_address.h>
18*4882a593Smuzhiyun #include <linux/of.h>
19*4882a593Smuzhiyun #include <linux/of_irq.h>
20*4882a593Smuzhiyun #include <linux/sched_clock.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define TIMER_CTRL 0x0
24*4882a593Smuzhiyun #define TIMER_CTRL_ENABLE BIT(0)
25*4882a593Smuzhiyun #define TIMER_CTRL_IE BIT(3)
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define TIMER_VALUE 0x4
28*4882a593Smuzhiyun #define TIMER_RELOAD 0x8
29*4882a593Smuzhiyun #define TIMER_INT 0xc
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct clockevent_mps2 {
32*4882a593Smuzhiyun void __iomem *reg;
33*4882a593Smuzhiyun u32 clock_count_per_tick;
34*4882a593Smuzhiyun struct clock_event_device clkevt;
35*4882a593Smuzhiyun };
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static void __iomem *sched_clock_base;
38*4882a593Smuzhiyun
mps2_sched_read(void)39*4882a593Smuzhiyun static u64 notrace mps2_sched_read(void)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun return ~readl_relaxed(sched_clock_base + TIMER_VALUE);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
to_mps2_clkevt(struct clock_event_device * c)44*4882a593Smuzhiyun static inline struct clockevent_mps2 *to_mps2_clkevt(struct clock_event_device *c)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun return container_of(c, struct clockevent_mps2, clkevt);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
clockevent_mps2_writel(u32 val,struct clock_event_device * c,u32 offset)49*4882a593Smuzhiyun static void clockevent_mps2_writel(u32 val, struct clock_event_device *c, u32 offset)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun writel_relaxed(val, to_mps2_clkevt(c)->reg + offset);
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun
mps2_timer_shutdown(struct clock_event_device * ce)54*4882a593Smuzhiyun static int mps2_timer_shutdown(struct clock_event_device *ce)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun clockevent_mps2_writel(0, ce, TIMER_RELOAD);
57*4882a593Smuzhiyun clockevent_mps2_writel(0, ce, TIMER_CTRL);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun return 0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun
mps2_timer_set_next_event(unsigned long next,struct clock_event_device * ce)62*4882a593Smuzhiyun static int mps2_timer_set_next_event(unsigned long next, struct clock_event_device *ce)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun clockevent_mps2_writel(next, ce, TIMER_VALUE);
65*4882a593Smuzhiyun clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return 0;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
mps2_timer_set_periodic(struct clock_event_device * ce)70*4882a593Smuzhiyun static int mps2_timer_set_periodic(struct clock_event_device *ce)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun u32 clock_count_per_tick = to_mps2_clkevt(ce)->clock_count_per_tick;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_RELOAD);
75*4882a593Smuzhiyun clockevent_mps2_writel(clock_count_per_tick, ce, TIMER_VALUE);
76*4882a593Smuzhiyun clockevent_mps2_writel(TIMER_CTRL_IE | TIMER_CTRL_ENABLE, ce, TIMER_CTRL);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun return 0;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
mps2_timer_interrupt(int irq,void * dev_id)81*4882a593Smuzhiyun static irqreturn_t mps2_timer_interrupt(int irq, void *dev_id)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun struct clockevent_mps2 *ce = dev_id;
84*4882a593Smuzhiyun u32 status = readl_relaxed(ce->reg + TIMER_INT);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun if (!status) {
87*4882a593Smuzhiyun pr_warn("spurious interrupt\n");
88*4882a593Smuzhiyun return IRQ_NONE;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun writel_relaxed(1, ce->reg + TIMER_INT);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun ce->clkevt.event_handler(&ce->clkevt);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return IRQ_HANDLED;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
mps2_clockevent_init(struct device_node * np)98*4882a593Smuzhiyun static int __init mps2_clockevent_init(struct device_node *np)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun void __iomem *base;
101*4882a593Smuzhiyun struct clk *clk = NULL;
102*4882a593Smuzhiyun struct clockevent_mps2 *ce;
103*4882a593Smuzhiyun u32 rate;
104*4882a593Smuzhiyun int irq, ret;
105*4882a593Smuzhiyun const char *name = "mps2-clkevt";
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun ret = of_property_read_u32(np, "clock-frequency", &rate);
108*4882a593Smuzhiyun if (ret) {
109*4882a593Smuzhiyun clk = of_clk_get(np, 0);
110*4882a593Smuzhiyun if (IS_ERR(clk)) {
111*4882a593Smuzhiyun ret = PTR_ERR(clk);
112*4882a593Smuzhiyun pr_err("failed to get clock for clockevent: %d\n", ret);
113*4882a593Smuzhiyun goto out;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun ret = clk_prepare_enable(clk);
117*4882a593Smuzhiyun if (ret) {
118*4882a593Smuzhiyun pr_err("failed to enable clock for clockevent: %d\n", ret);
119*4882a593Smuzhiyun goto out_clk_put;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun rate = clk_get_rate(clk);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun base = of_iomap(np, 0);
126*4882a593Smuzhiyun if (!base) {
127*4882a593Smuzhiyun ret = -EADDRNOTAVAIL;
128*4882a593Smuzhiyun pr_err("failed to map register for clockevent: %d\n", ret);
129*4882a593Smuzhiyun goto out_clk_disable;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun irq = irq_of_parse_and_map(np, 0);
133*4882a593Smuzhiyun if (!irq) {
134*4882a593Smuzhiyun ret = -ENOENT;
135*4882a593Smuzhiyun pr_err("failed to get irq for clockevent: %d\n", ret);
136*4882a593Smuzhiyun goto out_iounmap;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun ce = kzalloc(sizeof(*ce), GFP_KERNEL);
140*4882a593Smuzhiyun if (!ce) {
141*4882a593Smuzhiyun ret = -ENOMEM;
142*4882a593Smuzhiyun goto out_iounmap;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun ce->reg = base;
146*4882a593Smuzhiyun ce->clock_count_per_tick = DIV_ROUND_CLOSEST(rate, HZ);
147*4882a593Smuzhiyun ce->clkevt.irq = irq;
148*4882a593Smuzhiyun ce->clkevt.name = name;
149*4882a593Smuzhiyun ce->clkevt.rating = 200;
150*4882a593Smuzhiyun ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
151*4882a593Smuzhiyun ce->clkevt.cpumask = cpu_possible_mask;
152*4882a593Smuzhiyun ce->clkevt.set_state_shutdown = mps2_timer_shutdown;
153*4882a593Smuzhiyun ce->clkevt.set_state_periodic = mps2_timer_set_periodic;
154*4882a593Smuzhiyun ce->clkevt.set_state_oneshot = mps2_timer_shutdown;
155*4882a593Smuzhiyun ce->clkevt.set_next_event = mps2_timer_set_next_event;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Ensure timer is disabled */
158*4882a593Smuzhiyun writel_relaxed(0, base + TIMER_CTRL);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun ret = request_irq(irq, mps2_timer_interrupt, IRQF_TIMER, name, ce);
161*4882a593Smuzhiyun if (ret) {
162*4882a593Smuzhiyun pr_err("failed to request irq for clockevent: %d\n", ret);
163*4882a593Smuzhiyun goto out_kfree;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun clockevents_config_and_register(&ce->clkevt, rate, 0xf, 0xffffffff);
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun return 0;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun out_kfree:
171*4882a593Smuzhiyun kfree(ce);
172*4882a593Smuzhiyun out_iounmap:
173*4882a593Smuzhiyun iounmap(base);
174*4882a593Smuzhiyun out_clk_disable:
175*4882a593Smuzhiyun /* clk_{disable, unprepare, put}() can handle NULL as a parameter */
176*4882a593Smuzhiyun clk_disable_unprepare(clk);
177*4882a593Smuzhiyun out_clk_put:
178*4882a593Smuzhiyun clk_put(clk);
179*4882a593Smuzhiyun out:
180*4882a593Smuzhiyun return ret;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
mps2_clocksource_init(struct device_node * np)183*4882a593Smuzhiyun static int __init mps2_clocksource_init(struct device_node *np)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun void __iomem *base;
186*4882a593Smuzhiyun struct clk *clk = NULL;
187*4882a593Smuzhiyun u32 rate;
188*4882a593Smuzhiyun int ret;
189*4882a593Smuzhiyun const char *name = "mps2-clksrc";
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun ret = of_property_read_u32(np, "clock-frequency", &rate);
192*4882a593Smuzhiyun if (ret) {
193*4882a593Smuzhiyun clk = of_clk_get(np, 0);
194*4882a593Smuzhiyun if (IS_ERR(clk)) {
195*4882a593Smuzhiyun ret = PTR_ERR(clk);
196*4882a593Smuzhiyun pr_err("failed to get clock for clocksource: %d\n", ret);
197*4882a593Smuzhiyun goto out;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun ret = clk_prepare_enable(clk);
201*4882a593Smuzhiyun if (ret) {
202*4882a593Smuzhiyun pr_err("failed to enable clock for clocksource: %d\n", ret);
203*4882a593Smuzhiyun goto out_clk_put;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun rate = clk_get_rate(clk);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun base = of_iomap(np, 0);
210*4882a593Smuzhiyun if (!base) {
211*4882a593Smuzhiyun ret = -EADDRNOTAVAIL;
212*4882a593Smuzhiyun pr_err("failed to map register for clocksource: %d\n", ret);
213*4882a593Smuzhiyun goto out_clk_disable;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /* Ensure timer is disabled */
217*4882a593Smuzhiyun writel_relaxed(0, base + TIMER_CTRL);
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* ... and set it up as free-running clocksource */
220*4882a593Smuzhiyun writel_relaxed(0xffffffff, base + TIMER_VALUE);
221*4882a593Smuzhiyun writel_relaxed(0xffffffff, base + TIMER_RELOAD);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun writel_relaxed(TIMER_CTRL_ENABLE, base + TIMER_CTRL);
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun ret = clocksource_mmio_init(base + TIMER_VALUE, name,
226*4882a593Smuzhiyun rate, 200, 32,
227*4882a593Smuzhiyun clocksource_mmio_readl_down);
228*4882a593Smuzhiyun if (ret) {
229*4882a593Smuzhiyun pr_err("failed to init clocksource: %d\n", ret);
230*4882a593Smuzhiyun goto out_iounmap;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun sched_clock_base = base;
234*4882a593Smuzhiyun sched_clock_register(mps2_sched_read, 32, rate);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun return 0;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun out_iounmap:
239*4882a593Smuzhiyun iounmap(base);
240*4882a593Smuzhiyun out_clk_disable:
241*4882a593Smuzhiyun /* clk_{disable, unprepare, put}() can handle NULL as a parameter */
242*4882a593Smuzhiyun clk_disable_unprepare(clk);
243*4882a593Smuzhiyun out_clk_put:
244*4882a593Smuzhiyun clk_put(clk);
245*4882a593Smuzhiyun out:
246*4882a593Smuzhiyun return ret;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
mps2_timer_init(struct device_node * np)249*4882a593Smuzhiyun static int __init mps2_timer_init(struct device_node *np)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun static int has_clocksource, has_clockevent;
252*4882a593Smuzhiyun int ret;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun if (!has_clocksource) {
255*4882a593Smuzhiyun ret = mps2_clocksource_init(np);
256*4882a593Smuzhiyun if (!ret) {
257*4882a593Smuzhiyun has_clocksource = 1;
258*4882a593Smuzhiyun return 0;
259*4882a593Smuzhiyun }
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun if (!has_clockevent) {
263*4882a593Smuzhiyun ret = mps2_clockevent_init(np);
264*4882a593Smuzhiyun if (!ret) {
265*4882a593Smuzhiyun has_clockevent = 1;
266*4882a593Smuzhiyun return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun return 0;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun TIMER_OF_DECLARE(mps2_timer, "arm,mps2-timer", mps2_timer_init);
274