1e45e778fSFabio Estevam // SPDX-License-Identifier: GPL-2.0+
2e45e778fSFabio Estevam //
3e45e778fSFabio Estevam //  Copyright (C) 2000-2001 Deep Blue Solutions
4e45e778fSFabio Estevam //  Copyright (C) 2002 Shane Nay ([email protected])
5e45e778fSFabio Estevam //  Copyright (C) 2006-2007 Pavel Pisa ([email protected])
6e45e778fSFabio Estevam //  Copyright (C) 2008 Juergen Beisert ([email protected])
7e45e778fSFabio Estevam //  Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
8c74512bfSShawn Guo 
9c74512bfSShawn Guo #include <linux/err.h>
10c74512bfSShawn Guo #include <linux/interrupt.h>
11c74512bfSShawn Guo #include <linux/irq.h>
12c74512bfSShawn Guo #include <linux/clockchips.h>
13c74512bfSShawn Guo #include <linux/clk.h>
14c74512bfSShawn Guo #include <linux/of.h>
15c74512bfSShawn Guo #include <linux/of_address.h>
16c74512bfSShawn Guo #include <linux/of_irq.h>
17c74512bfSShawn Guo #include <linux/stmp_device.h>
1838ff87f7SStephen Boyd #include <linux/sched_clock.h>
19c74512bfSShawn Guo 
20c74512bfSShawn Guo /*
21c74512bfSShawn Guo  * There are 2 versions of the timrot on Freescale MXS-based SoCs.
22c74512bfSShawn Guo  * The v1 on MX23 only gets 16 bits counter, while v2 on MX28
23c74512bfSShawn Guo  * extends the counter to 32 bits.
24c74512bfSShawn Guo  *
25c74512bfSShawn Guo  * The implementation uses two timers, one for clock_event and
26c74512bfSShawn Guo  * another for clocksource. MX28 uses timrot 0 and 1, while MX23
27c74512bfSShawn Guo  * uses 0 and 2.
28c74512bfSShawn Guo  */
29c74512bfSShawn Guo 
30c74512bfSShawn Guo #define MX23_TIMROT_VERSION_OFFSET	0x0a0
31c74512bfSShawn Guo #define MX28_TIMROT_VERSION_OFFSET	0x120
32c74512bfSShawn Guo #define BP_TIMROT_MAJOR_VERSION		24
33c74512bfSShawn Guo #define BV_TIMROT_VERSION_1		0x01
34c74512bfSShawn Guo #define BV_TIMROT_VERSION_2		0x02
35c74512bfSShawn Guo #define timrot_is_v1()	(timrot_major_version == BV_TIMROT_VERSION_1)
36c74512bfSShawn Guo 
37c74512bfSShawn Guo /*
38c74512bfSShawn Guo  * There are 4 registers for each timrotv2 instance, and 2 registers
39c74512bfSShawn Guo  * for each timrotv1. So address step 0x40 in macros below strides
40c74512bfSShawn Guo  * one instance of timrotv2 while two instances of timrotv1.
41c74512bfSShawn Guo  *
42c74512bfSShawn Guo  * As the result, HW_TIMROT_XXXn(1) defines the address of timrot1
43c74512bfSShawn Guo  * on MX28 while timrot2 on MX23.
44c74512bfSShawn Guo  */
45c74512bfSShawn Guo /* common between v1 and v2 */
46c74512bfSShawn Guo #define HW_TIMROT_ROTCTRL		0x00
47c74512bfSShawn Guo #define HW_TIMROT_TIMCTRLn(n)		(0x20 + (n) * 0x40)
48c74512bfSShawn Guo /* v1 only */
49c74512bfSShawn Guo #define HW_TIMROT_TIMCOUNTn(n)		(0x30 + (n) * 0x40)
50c74512bfSShawn Guo /* v2 only */
51c74512bfSShawn Guo #define HW_TIMROT_RUNNING_COUNTn(n)	(0x30 + (n) * 0x40)
52c74512bfSShawn Guo #define HW_TIMROT_FIXED_COUNTn(n)	(0x40 + (n) * 0x40)
53c74512bfSShawn Guo 
54c74512bfSShawn Guo #define BM_TIMROT_TIMCTRLn_RELOAD	(1 << 6)
55c74512bfSShawn Guo #define BM_TIMROT_TIMCTRLn_UPDATE	(1 << 7)
56c74512bfSShawn Guo #define BM_TIMROT_TIMCTRLn_IRQ_EN	(1 << 14)
57c74512bfSShawn Guo #define BM_TIMROT_TIMCTRLn_IRQ		(1 << 15)
58c74512bfSShawn Guo #define BP_TIMROT_TIMCTRLn_SELECT	0
59c74512bfSShawn Guo #define BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL		0x8
60c74512bfSShawn Guo #define BV_TIMROTv2_TIMCTRLn_SELECT__32KHZ_XTAL		0xb
61c74512bfSShawn Guo #define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS	0xf
62c74512bfSShawn Guo 
63c74512bfSShawn Guo static struct clock_event_device mxs_clockevent_device;
64c74512bfSShawn Guo 
65c74512bfSShawn Guo static void __iomem *mxs_timrot_base;
66c74512bfSShawn Guo static u32 timrot_major_version;
67c74512bfSShawn Guo 
timrot_irq_disable(void)68c74512bfSShawn Guo static inline void timrot_irq_disable(void)
69c74512bfSShawn Guo {
70c74512bfSShawn Guo 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
71c74512bfSShawn Guo 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
72c74512bfSShawn Guo }
73c74512bfSShawn Guo 
timrot_irq_enable(void)74c74512bfSShawn Guo static inline void timrot_irq_enable(void)
75c74512bfSShawn Guo {
76c74512bfSShawn Guo 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ_EN, mxs_timrot_base +
77c74512bfSShawn Guo 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_SET);
78c74512bfSShawn Guo }
79c74512bfSShawn Guo 
timrot_irq_acknowledge(void)80c74512bfSShawn Guo static void timrot_irq_acknowledge(void)
81c74512bfSShawn Guo {
82c74512bfSShawn Guo 	__raw_writel(BM_TIMROT_TIMCTRLn_IRQ, mxs_timrot_base +
83c74512bfSShawn Guo 		     HW_TIMROT_TIMCTRLn(0) + STMP_OFFSET_REG_CLR);
84c74512bfSShawn Guo }
85c74512bfSShawn Guo 
timrotv1_get_cycles(struct clocksource * cs)86a5a1d1c2SThomas Gleixner static u64 timrotv1_get_cycles(struct clocksource *cs)
87c74512bfSShawn Guo {
88c74512bfSShawn Guo 	return ~((__raw_readl(mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1))
89c74512bfSShawn Guo 			& 0xffff0000) >> 16);
90c74512bfSShawn Guo }
91c74512bfSShawn Guo 
timrotv1_set_next_event(unsigned long evt,struct clock_event_device * dev)92c74512bfSShawn Guo static int timrotv1_set_next_event(unsigned long evt,
93c74512bfSShawn Guo 					struct clock_event_device *dev)
94c74512bfSShawn Guo {
95c74512bfSShawn Guo 	/* timrot decrements the count */
96c74512bfSShawn Guo 	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(0));
97c74512bfSShawn Guo 
98c74512bfSShawn Guo 	return 0;
99c74512bfSShawn Guo }
100c74512bfSShawn Guo 
timrotv2_set_next_event(unsigned long evt,struct clock_event_device * dev)101c74512bfSShawn Guo static int timrotv2_set_next_event(unsigned long evt,
102c74512bfSShawn Guo 					struct clock_event_device *dev)
103c74512bfSShawn Guo {
104c74512bfSShawn Guo 	/* timrot decrements the count */
105c74512bfSShawn Guo 	__raw_writel(evt, mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(0));
106c74512bfSShawn Guo 
107c74512bfSShawn Guo 	return 0;
108c74512bfSShawn Guo }
109c74512bfSShawn Guo 
mxs_timer_interrupt(int irq,void * dev_id)110c74512bfSShawn Guo static irqreturn_t mxs_timer_interrupt(int irq, void *dev_id)
111c74512bfSShawn Guo {
112c74512bfSShawn Guo 	struct clock_event_device *evt = dev_id;
113c74512bfSShawn Guo 
114c74512bfSShawn Guo 	timrot_irq_acknowledge();
115c74512bfSShawn Guo 	evt->event_handler(evt);
116c74512bfSShawn Guo 
117c74512bfSShawn Guo 	return IRQ_HANDLED;
118c74512bfSShawn Guo }
119c74512bfSShawn Guo 
mxs_irq_clear(char * state)120eb8703e2SViresh Kumar static void mxs_irq_clear(char *state)
121c74512bfSShawn Guo {
122c74512bfSShawn Guo 	/* Disable interrupt in timer module */
123c74512bfSShawn Guo 	timrot_irq_disable();
124c74512bfSShawn Guo 
125c74512bfSShawn Guo 	/* Set event time into the furthest future */
126c74512bfSShawn Guo 	if (timrot_is_v1())
127eb8703e2SViresh Kumar 		__raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
128c74512bfSShawn Guo 	else
129c74512bfSShawn Guo 		__raw_writel(0xffffffff,
130c74512bfSShawn Guo 			     mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
131c74512bfSShawn Guo 
132c74512bfSShawn Guo 	/* Clear pending interrupt */
133c74512bfSShawn Guo 	timrot_irq_acknowledge();
134*7da39069STom Rix 	pr_debug("%s: changing mode to %s\n", __func__, state);
135c74512bfSShawn Guo }
136eb8703e2SViresh Kumar 
mxs_shutdown(struct clock_event_device * evt)137eb8703e2SViresh Kumar static int mxs_shutdown(struct clock_event_device *evt)
138eb8703e2SViresh Kumar {
139eb8703e2SViresh Kumar 	mxs_irq_clear("shutdown");
140eb8703e2SViresh Kumar 
141eb8703e2SViresh Kumar 	return 0;
142eb8703e2SViresh Kumar }
143eb8703e2SViresh Kumar 
mxs_set_oneshot(struct clock_event_device * evt)144eb8703e2SViresh Kumar static int mxs_set_oneshot(struct clock_event_device *evt)
145eb8703e2SViresh Kumar {
146eb8703e2SViresh Kumar 	if (clockevent_state_oneshot(evt))
147eb8703e2SViresh Kumar 		mxs_irq_clear("oneshot");
148eb8703e2SViresh Kumar 	timrot_irq_enable();
149eb8703e2SViresh Kumar 	return 0;
150c74512bfSShawn Guo }
151c74512bfSShawn Guo 
152c74512bfSShawn Guo static struct clock_event_device mxs_clockevent_device = {
153c74512bfSShawn Guo 	.name			= "mxs_timrot",
154c74512bfSShawn Guo 	.features		= CLOCK_EVT_FEAT_ONESHOT,
155eb8703e2SViresh Kumar 	.set_state_shutdown	= mxs_shutdown,
156eb8703e2SViresh Kumar 	.set_state_oneshot	= mxs_set_oneshot,
157eb8703e2SViresh Kumar 	.tick_resume		= mxs_shutdown,
158c74512bfSShawn Guo 	.set_next_event		= timrotv2_set_next_event,
159c74512bfSShawn Guo 	.rating			= 200,
160c74512bfSShawn Guo };
161c74512bfSShawn Guo 
mxs_clockevent_init(struct clk * timer_clk)162c74512bfSShawn Guo static int __init mxs_clockevent_init(struct clk *timer_clk)
163c74512bfSShawn Guo {
164c74512bfSShawn Guo 	if (timrot_is_v1())
165c74512bfSShawn Guo 		mxs_clockevent_device.set_next_event = timrotv1_set_next_event;
166c74512bfSShawn Guo 	mxs_clockevent_device.cpumask = cpumask_of(0);
167c74512bfSShawn Guo 	clockevents_config_and_register(&mxs_clockevent_device,
168c74512bfSShawn Guo 					clk_get_rate(timer_clk),
169c74512bfSShawn Guo 					timrot_is_v1() ? 0xf : 0x2,
170c74512bfSShawn Guo 					timrot_is_v1() ? 0xfffe : 0xfffffffe);
171c74512bfSShawn Guo 
172c74512bfSShawn Guo 	return 0;
173c74512bfSShawn Guo }
174c74512bfSShawn Guo 
175c74512bfSShawn Guo static struct clocksource clocksource_mxs = {
176c74512bfSShawn Guo 	.name		= "mxs_timer",
177c74512bfSShawn Guo 	.rating		= 200,
178c74512bfSShawn Guo 	.read		= timrotv1_get_cycles,
179c74512bfSShawn Guo 	.mask		= CLOCKSOURCE_MASK(16),
180c74512bfSShawn Guo 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
181c74512bfSShawn Guo };
182c74512bfSShawn Guo 
mxs_read_sched_clock_v2(void)183fcfca6efSStephen Boyd static u64 notrace mxs_read_sched_clock_v2(void)
184c74512bfSShawn Guo {
185c74512bfSShawn Guo 	return ~readl_relaxed(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
186c74512bfSShawn Guo }
187c74512bfSShawn Guo 
mxs_clocksource_init(struct clk * timer_clk)188c74512bfSShawn Guo static int __init mxs_clocksource_init(struct clk *timer_clk)
189c74512bfSShawn Guo {
190c74512bfSShawn Guo 	unsigned int c = clk_get_rate(timer_clk);
191c74512bfSShawn Guo 
192c74512bfSShawn Guo 	if (timrot_is_v1())
193c74512bfSShawn Guo 		clocksource_register_hz(&clocksource_mxs, c);
194c74512bfSShawn Guo 	else {
195c74512bfSShawn Guo 		clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
196c74512bfSShawn Guo 			"mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
197fcfca6efSStephen Boyd 		sched_clock_register(mxs_read_sched_clock_v2, 32, c);
198c74512bfSShawn Guo 	}
199c74512bfSShawn Guo 
200c74512bfSShawn Guo 	return 0;
201c74512bfSShawn Guo }
202c74512bfSShawn Guo 
mxs_timer_init(struct device_node * np)203e1d2b9f0SDaniel Lezcano static int __init mxs_timer_init(struct device_node *np)
204c74512bfSShawn Guo {
205c74512bfSShawn Guo 	struct clk *timer_clk;
206e1d2b9f0SDaniel Lezcano 	int irq, ret;
207c74512bfSShawn Guo 
208c74512bfSShawn Guo 	mxs_timrot_base = of_iomap(np, 0);
209c74512bfSShawn Guo 	WARN_ON(!mxs_timrot_base);
210c74512bfSShawn Guo 
211c74512bfSShawn Guo 	timer_clk = of_clk_get(np, 0);
212c74512bfSShawn Guo 	if (IS_ERR(timer_clk)) {
213c74512bfSShawn Guo 		pr_err("%s: failed to get clk\n", __func__);
214e1d2b9f0SDaniel Lezcano 		return PTR_ERR(timer_clk);
215c74512bfSShawn Guo 	}
216c74512bfSShawn Guo 
217e1d2b9f0SDaniel Lezcano 	ret = clk_prepare_enable(timer_clk);
218e1d2b9f0SDaniel Lezcano 	if (ret)
219e1d2b9f0SDaniel Lezcano 		return ret;
220c74512bfSShawn Guo 
221c74512bfSShawn Guo 	/*
222c74512bfSShawn Guo 	 * Initialize timers to a known state
223c74512bfSShawn Guo 	 */
224c74512bfSShawn Guo 	stmp_reset_block(mxs_timrot_base + HW_TIMROT_ROTCTRL);
225c74512bfSShawn Guo 
226c74512bfSShawn Guo 	/* get timrot version */
227c74512bfSShawn Guo 	timrot_major_version = __raw_readl(mxs_timrot_base +
228c74512bfSShawn Guo 			(of_device_is_compatible(np, "fsl,imx23-timrot") ?
229c74512bfSShawn Guo 						MX23_TIMROT_VERSION_OFFSET :
230c74512bfSShawn Guo 						MX28_TIMROT_VERSION_OFFSET));
231c74512bfSShawn Guo 	timrot_major_version >>= BP_TIMROT_MAJOR_VERSION;
232c74512bfSShawn Guo 
233c74512bfSShawn Guo 	/* one for clock_event */
234c74512bfSShawn Guo 	__raw_writel((timrot_is_v1() ?
235c74512bfSShawn Guo 			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
236c74512bfSShawn Guo 			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
237c74512bfSShawn Guo 			BM_TIMROT_TIMCTRLn_UPDATE |
238c74512bfSShawn Guo 			BM_TIMROT_TIMCTRLn_IRQ_EN,
239c74512bfSShawn Guo 			mxs_timrot_base + HW_TIMROT_TIMCTRLn(0));
240c74512bfSShawn Guo 
241c74512bfSShawn Guo 	/* another for clocksource */
242c74512bfSShawn Guo 	__raw_writel((timrot_is_v1() ?
243c74512bfSShawn Guo 			BV_TIMROTv1_TIMCTRLn_SELECT__32KHZ_XTAL :
244c74512bfSShawn Guo 			BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS) |
245c74512bfSShawn Guo 			BM_TIMROT_TIMCTRLn_RELOAD,
246c74512bfSShawn Guo 			mxs_timrot_base + HW_TIMROT_TIMCTRLn(1));
247c74512bfSShawn Guo 
248c74512bfSShawn Guo 	/* set clocksource timer fixed count to the maximum */
249c74512bfSShawn Guo 	if (timrot_is_v1())
250c74512bfSShawn Guo 		__raw_writel(0xffff,
251c74512bfSShawn Guo 			mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1));
252c74512bfSShawn Guo 	else
253c74512bfSShawn Guo 		__raw_writel(0xffffffff,
254c74512bfSShawn Guo 			mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1));
255c74512bfSShawn Guo 
256c74512bfSShawn Guo 	/* init and register the timer to the framework */
257e1d2b9f0SDaniel Lezcano 	ret = mxs_clocksource_init(timer_clk);
258e1d2b9f0SDaniel Lezcano 	if (ret)
259e1d2b9f0SDaniel Lezcano 		return ret;
260e1d2b9f0SDaniel Lezcano 
261e1d2b9f0SDaniel Lezcano 	ret = mxs_clockevent_init(timer_clk);
262e1d2b9f0SDaniel Lezcano 	if (ret)
263e1d2b9f0SDaniel Lezcano 		return ret;
264c74512bfSShawn Guo 
265c74512bfSShawn Guo 	/* Make irqs happen */
266c74512bfSShawn Guo 	irq = irq_of_parse_and_map(np, 0);
267e1d2b9f0SDaniel Lezcano 	if (irq <= 0)
268e1d2b9f0SDaniel Lezcano 		return -EINVAL;
269e1d2b9f0SDaniel Lezcano 
270cc2550b4Safzal mohammed 	return request_irq(irq, mxs_timer_interrupt, IRQF_TIMER | IRQF_IRQPOLL,
271cc2550b4Safzal mohammed 			   "MXS Timer Tick", &mxs_clockevent_device);
272c74512bfSShawn Guo }
27317273395SDaniel Lezcano TIMER_OF_DECLARE(mxs, "fsl,timrot", mxs_timer_init);
274