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