xref: /OK3568_Linux_fs/kernel/drivers/clocksource/mps2-timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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