• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  linux/arch/arm/plat-mxc/time.c
3  *
4  *  Copyright (C) 2000-2001 Deep Blue Solutions
5  *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
6  *  Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
7  *  Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301, USA.
22  */
23 
24 #include <linux/interrupt.h>
25 #include <linux/irq.h>
26 #include <linux/clockchips.h>
27 #include <linux/clk.h>
28 #include <linux/err.h>
29 
30 #include <asm/sched_clock.h>
31 #include <asm/mach/time.h>
32 
33 #include "common.h"
34 #include "hardware.h"
35 
36 /*
37  * There are 2 versions of the timer hardware on Freescale MXC hardware.
38  * Version 1: MX1/MXL, MX21, MX27.
39  * Version 2: MX25, MX31, MX35, MX37, MX51
40  */
41 
42 /* defines common for all i.MX */
43 #define MXC_TCTL		0x00
44 #define MXC_TCTL_TEN		(1 << 0) /* Enable module */
45 #define MXC_TPRER		0x04
46 
47 /* MX1, MX21, MX27 */
48 #define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
49 #define MX1_2_TCTL_IRQEN	(1 << 4)
50 #define MX1_2_TCTL_FRR		(1 << 8)
51 #define MX1_2_TCMP		0x08
52 #define MX1_2_TCN		0x10
53 #define MX1_2_TSTAT		0x14
54 
55 /* MX21, MX27 */
56 #define MX2_TSTAT_CAPT		(1 << 1)
57 #define MX2_TSTAT_COMP		(1 << 0)
58 
59 /* MX31, MX35, MX25, MX5 */
60 #define V2_TCTL_WAITEN		(1 << 3) /* Wait enable mode */
61 #define V2_TCTL_CLK_IPG		(1 << 6)
62 #define V2_TCTL_CLK_PER		(2 << 6)
63 #define V2_TCTL_FRR		(1 << 9)
64 #define V2_IR			0x0c
65 #define V2_TSTAT		0x08
66 #define V2_TSTAT_OF1		(1 << 0)
67 #define V2_TCN			0x24
68 #define V2_TCMP			0x10
69 
70 #define timer_is_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
71 #define timer_is_v2()	(!timer_is_v1())
72 
73 static struct clock_event_device clockevent_mxc;
74 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
75 
76 static void __iomem *timer_base;
77 
gpt_irq_disable(void)78 static inline void gpt_irq_disable(void)
79 {
80 	unsigned int tmp;
81 
82 	if (timer_is_v2())
83 		__raw_writel(0, timer_base + V2_IR);
84 	else {
85 		tmp = __raw_readl(timer_base + MXC_TCTL);
86 		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
87 	}
88 }
89 
gpt_irq_enable(void)90 static inline void gpt_irq_enable(void)
91 {
92 	if (timer_is_v2())
93 		__raw_writel(1<<0, timer_base + V2_IR);
94 	else {
95 		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
96 			timer_base + MXC_TCTL);
97 	}
98 }
99 
gpt_irq_acknowledge(void)100 static void gpt_irq_acknowledge(void)
101 {
102 	if (timer_is_v1()) {
103 		if (cpu_is_mx1())
104 			__raw_writel(0, timer_base + MX1_2_TSTAT);
105 		else
106 			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
107 				timer_base + MX1_2_TSTAT);
108 	} else if (timer_is_v2())
109 		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
110 }
111 
112 static void __iomem *sched_clock_reg;
113 
mxc_read_sched_clock(void)114 static u32 notrace mxc_read_sched_clock(void)
115 {
116 	return sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
117 }
118 
mxc_clocksource_init(struct clk * timer_clk)119 static int __init mxc_clocksource_init(struct clk *timer_clk)
120 {
121 	unsigned int c = clk_get_rate(timer_clk);
122 	void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
123 
124 	sched_clock_reg = reg;
125 
126 	setup_sched_clock(mxc_read_sched_clock, 32, c);
127 	return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
128 			clocksource_mmio_readl_up);
129 }
130 
131 /* clock event */
132 
mx1_2_set_next_event(unsigned long evt,struct clock_event_device * unused)133 static int mx1_2_set_next_event(unsigned long evt,
134 			      struct clock_event_device *unused)
135 {
136 	unsigned long tcmp;
137 
138 	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
139 
140 	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
141 
142 	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
143 				-ETIME : 0;
144 }
145 
v2_set_next_event(unsigned long evt,struct clock_event_device * unused)146 static int v2_set_next_event(unsigned long evt,
147 			      struct clock_event_device *unused)
148 {
149 	unsigned long tcmp;
150 
151 	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
152 
153 	__raw_writel(tcmp, timer_base + V2_TCMP);
154 
155 	return evt < 0x7fffffff &&
156 		(int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
157 				-ETIME : 0;
158 }
159 
160 #ifdef DEBUG
161 static const char *clock_event_mode_label[] = {
162 	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
163 	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
164 	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
165 	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED",
166 	[CLOCK_EVT_MODE_RESUME]   = "CLOCK_EVT_MODE_RESUME",
167 };
168 #endif /* DEBUG */
169 
mxc_set_mode(enum clock_event_mode mode,struct clock_event_device * evt)170 static void mxc_set_mode(enum clock_event_mode mode,
171 				struct clock_event_device *evt)
172 {
173 	unsigned long flags;
174 
175 	/*
176 	 * The timer interrupt generation is disabled at least
177 	 * for enough time to call mxc_set_next_event()
178 	 */
179 	local_irq_save(flags);
180 
181 	/* Disable interrupt in GPT module */
182 	gpt_irq_disable();
183 
184 	if (mode != clockevent_mode) {
185 		/* Set event time into far-far future */
186 		if (timer_is_v2())
187 			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
188 					timer_base + V2_TCMP);
189 		else
190 			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
191 					timer_base + MX1_2_TCMP);
192 
193 		/* Clear pending interrupt */
194 		gpt_irq_acknowledge();
195 	}
196 
197 #ifdef DEBUG
198 	printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
199 		clock_event_mode_label[clockevent_mode],
200 		clock_event_mode_label[mode]);
201 #endif /* DEBUG */
202 
203 	/* Remember timer mode */
204 	clockevent_mode = mode;
205 	local_irq_restore(flags);
206 
207 	switch (mode) {
208 	case CLOCK_EVT_MODE_PERIODIC:
209 		printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
210 				"supported for i.MX\n");
211 		break;
212 	case CLOCK_EVT_MODE_ONESHOT:
213 	/*
214 	 * Do not put overhead of interrupt enable/disable into
215 	 * mxc_set_next_event(), the core has about 4 minutes
216 	 * to call mxc_set_next_event() or shutdown clock after
217 	 * mode switching
218 	 */
219 		local_irq_save(flags);
220 		gpt_irq_enable();
221 		local_irq_restore(flags);
222 		break;
223 	case CLOCK_EVT_MODE_SHUTDOWN:
224 	case CLOCK_EVT_MODE_UNUSED:
225 	case CLOCK_EVT_MODE_RESUME:
226 		/* Left event sources disabled, no more interrupts appear */
227 		break;
228 	}
229 }
230 
231 /*
232  * IRQ handler for the timer
233  */
mxc_timer_interrupt(int irq,void * dev_id)234 static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
235 {
236 	struct clock_event_device *evt = &clockevent_mxc;
237 	uint32_t tstat;
238 
239 	if (timer_is_v2())
240 		tstat = __raw_readl(timer_base + V2_TSTAT);
241 	else
242 		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
243 
244 	gpt_irq_acknowledge();
245 
246 	evt->event_handler(evt);
247 
248 	return IRQ_HANDLED;
249 }
250 
251 static struct irqaction mxc_timer_irq = {
252 	.name		= "i.MX Timer Tick",
253 	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
254 	.handler	= mxc_timer_interrupt,
255 };
256 
257 static struct clock_event_device clockevent_mxc = {
258 	.name		= "mxc_timer1",
259 	.features	= CLOCK_EVT_FEAT_ONESHOT,
260 	.set_mode	= mxc_set_mode,
261 	.set_next_event	= mx1_2_set_next_event,
262 	.rating		= 200,
263 };
264 
mxc_clockevent_init(struct clk * timer_clk)265 static int __init mxc_clockevent_init(struct clk *timer_clk)
266 {
267 	if (timer_is_v2())
268 		clockevent_mxc.set_next_event = v2_set_next_event;
269 
270 	clockevent_mxc.cpumask = cpumask_of(0);
271 	clockevents_config_and_register(&clockevent_mxc,
272 					clk_get_rate(timer_clk),
273 					0xff, 0xfffffffe);
274 
275 	return 0;
276 }
277 
mxc_timer_init(void __iomem * base,int irq)278 void __init mxc_timer_init(void __iomem *base, int irq)
279 {
280 	uint32_t tctl_val;
281 	struct clk *timer_clk;
282 	struct clk *timer_ipg_clk;
283 
284 	timer_clk = clk_get_sys("imx-gpt.0", "per");
285 	if (IS_ERR(timer_clk)) {
286 		pr_err("i.MX timer: unable to get clk\n");
287 		return;
288 	}
289 
290 	timer_ipg_clk = clk_get_sys("imx-gpt.0", "ipg");
291 	if (!IS_ERR(timer_ipg_clk))
292 		clk_prepare_enable(timer_ipg_clk);
293 
294 	clk_prepare_enable(timer_clk);
295 
296 	timer_base = base;
297 
298 	/*
299 	 * Initialise to a known state (all timers off, and timing reset)
300 	 */
301 
302 	__raw_writel(0, timer_base + MXC_TCTL);
303 	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
304 
305 	if (timer_is_v2())
306 		tctl_val = V2_TCTL_CLK_PER | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
307 	else
308 		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
309 
310 	__raw_writel(tctl_val, timer_base + MXC_TCTL);
311 
312 	/* init and register the timer to the framework */
313 	mxc_clocksource_init(timer_clk);
314 	mxc_clockevent_init(timer_clk);
315 
316 	/* Make irqs happen */
317 	setup_irq(irq, &mxc_timer_irq);
318 }
319