• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/plat-mxc/
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
29#include <mach/hardware.h>
30#include <asm/mach/time.h>
31#include <mach/common.h>
32
33/*
34 * There are 2 versions of the timer hardware on Freescale MXC hardware.
35 * Version 1: MX1/MXL, MX21, MX27.
36 * Version 2: MX25, MX31, MX35, MX37, MX51
37 */
38
39/* defines common for all i.MX */
40#define MXC_TCTL		0x00
41#define MXC_TCTL_TEN		(1 << 0) /* Enable module */
42#define MXC_TPRER		0x04
43
44/* MX1, MX21, MX27 */
45#define MX1_2_TCTL_CLK_PCLK1	(1 << 1)
46#define MX1_2_TCTL_IRQEN	(1 << 4)
47#define MX1_2_TCTL_FRR		(1 << 8)
48#define MX1_2_TCMP		0x08
49#define MX1_2_TCN		0x10
50#define MX1_2_TSTAT		0x14
51
52/* MX21, MX27 */
53#define MX2_TSTAT_CAPT		(1 << 1)
54#define MX2_TSTAT_COMP		(1 << 0)
55
56/* MX31, MX35, MX25, MXC91231, MX5 */
57#define V2_TCTL_WAITEN		(1 << 3) /* Wait enable mode */
58#define V2_TCTL_CLK_IPG		(1 << 6)
59#define V2_TCTL_FRR		(1 << 9)
60#define V2_IR			0x0c
61#define V2_TSTAT		0x08
62#define V2_TSTAT_OF1		(1 << 0)
63#define V2_TCN			0x24
64#define V2_TCMP			0x10
65
66#define timer_is_v1()	(cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
67#define timer_is_v2()	(!timer_is_v1())
68
69static struct clock_event_device clockevent_mxc;
70static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
71
72static void __iomem *timer_base;
73
74static inline void gpt_irq_disable(void)
75{
76	unsigned int tmp;
77
78	if (timer_is_v2())
79		__raw_writel(0, timer_base + V2_IR);
80	else {
81		tmp = __raw_readl(timer_base + MXC_TCTL);
82		__raw_writel(tmp & ~MX1_2_TCTL_IRQEN, timer_base + MXC_TCTL);
83	}
84}
85
86static inline void gpt_irq_enable(void)
87{
88	if (timer_is_v2())
89		__raw_writel(1<<0, timer_base + V2_IR);
90	else {
91		__raw_writel(__raw_readl(timer_base + MXC_TCTL) | MX1_2_TCTL_IRQEN,
92			timer_base + MXC_TCTL);
93	}
94}
95
96static void gpt_irq_acknowledge(void)
97{
98	if (timer_is_v1()) {
99		if (cpu_is_mx1())
100			__raw_writel(0, timer_base + MX1_2_TSTAT);
101		else
102			__raw_writel(MX2_TSTAT_CAPT | MX2_TSTAT_COMP,
103				timer_base + MX1_2_TSTAT);
104	} else if (timer_is_v2())
105		__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
106}
107
108static cycle_t mx1_2_get_cycles(struct clocksource *cs)
109{
110	return __raw_readl(timer_base + MX1_2_TCN);
111}
112
113static cycle_t v2_get_cycles(struct clocksource *cs)
114{
115	return __raw_readl(timer_base + V2_TCN);
116}
117
118static struct clocksource clocksource_mxc = {
119	.name 		= "mxc_timer1",
120	.rating		= 200,
121	.read		= mx1_2_get_cycles,
122	.mask		= CLOCKSOURCE_MASK(32),
123	.shift 		= 20,
124	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
125};
126
127static int __init mxc_clocksource_init(struct clk *timer_clk)
128{
129	unsigned int c = clk_get_rate(timer_clk);
130
131	if (timer_is_v2())
132		clocksource_mxc.read = v2_get_cycles;
133
134	clocksource_mxc.mult = clocksource_hz2mult(c,
135					clocksource_mxc.shift);
136	clocksource_register(&clocksource_mxc);
137
138	return 0;
139}
140
141/* clock event */
142
143static int mx1_2_set_next_event(unsigned long evt,
144			      struct clock_event_device *unused)
145{
146	unsigned long tcmp;
147
148	tcmp = __raw_readl(timer_base + MX1_2_TCN) + evt;
149
150	__raw_writel(tcmp, timer_base + MX1_2_TCMP);
151
152	return (int)(tcmp - __raw_readl(timer_base + MX1_2_TCN)) < 0 ?
153				-ETIME : 0;
154}
155
156static int v2_set_next_event(unsigned long evt,
157			      struct clock_event_device *unused)
158{
159	unsigned long tcmp;
160
161	tcmp = __raw_readl(timer_base + V2_TCN) + evt;
162
163	__raw_writel(tcmp, timer_base + V2_TCMP);
164
165	return (int)(tcmp - __raw_readl(timer_base + V2_TCN)) < 0 ?
166				-ETIME : 0;
167}
168
169#ifdef DEBUG
170static const char *clock_event_mode_label[] = {
171	[CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
172	[CLOCK_EVT_MODE_ONESHOT]  = "CLOCK_EVT_MODE_ONESHOT",
173	[CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
174	[CLOCK_EVT_MODE_UNUSED]   = "CLOCK_EVT_MODE_UNUSED"
175};
176#endif /* DEBUG */
177
178static void mxc_set_mode(enum clock_event_mode mode,
179				struct clock_event_device *evt)
180{
181	unsigned long flags;
182
183	/*
184	 * The timer interrupt generation is disabled at least
185	 * for enough time to call mxc_set_next_event()
186	 */
187	local_irq_save(flags);
188
189	/* Disable interrupt in GPT module */
190	gpt_irq_disable();
191
192	if (mode != clockevent_mode) {
193		/* Set event time into far-far future */
194		if (timer_is_v2())
195			__raw_writel(__raw_readl(timer_base + V2_TCN) - 3,
196					timer_base + V2_TCMP);
197		else
198			__raw_writel(__raw_readl(timer_base + MX1_2_TCN) - 3,
199					timer_base + MX1_2_TCMP);
200
201		/* Clear pending interrupt */
202		gpt_irq_acknowledge();
203	}
204
205#ifdef DEBUG
206	printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
207		clock_event_mode_label[clockevent_mode],
208		clock_event_mode_label[mode]);
209#endif /* DEBUG */
210
211	/* Remember timer mode */
212	clockevent_mode = mode;
213	local_irq_restore(flags);
214
215	switch (mode) {
216	case CLOCK_EVT_MODE_PERIODIC:
217		printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
218				"supported for i.MX\n");
219		break;
220	case CLOCK_EVT_MODE_ONESHOT:
221	/*
222	 * Do not put overhead of interrupt enable/disable into
223	 * mxc_set_next_event(), the core has about 4 minutes
224	 * to call mxc_set_next_event() or shutdown clock after
225	 * mode switching
226	 */
227		local_irq_save(flags);
228		gpt_irq_enable();
229		local_irq_restore(flags);
230		break;
231	case CLOCK_EVT_MODE_SHUTDOWN:
232	case CLOCK_EVT_MODE_UNUSED:
233	case CLOCK_EVT_MODE_RESUME:
234		/* Left event sources disabled, no more interrupts appear */
235		break;
236	}
237}
238
239/*
240 * IRQ handler for the timer
241 */
242static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
243{
244	struct clock_event_device *evt = &clockevent_mxc;
245	uint32_t tstat;
246
247	if (timer_is_v2())
248		tstat = __raw_readl(timer_base + V2_TSTAT);
249	else
250		tstat = __raw_readl(timer_base + MX1_2_TSTAT);
251
252	gpt_irq_acknowledge();
253
254	evt->event_handler(evt);
255
256	return IRQ_HANDLED;
257}
258
259static struct irqaction mxc_timer_irq = {
260	.name		= "i.MX Timer Tick",
261	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
262	.handler	= mxc_timer_interrupt,
263};
264
265static struct clock_event_device clockevent_mxc = {
266	.name		= "mxc_timer1",
267	.features	= CLOCK_EVT_FEAT_ONESHOT,
268	.shift		= 32,
269	.set_mode	= mxc_set_mode,
270	.set_next_event	= mx1_2_set_next_event,
271	.rating		= 200,
272};
273
274static int __init mxc_clockevent_init(struct clk *timer_clk)
275{
276	unsigned int c = clk_get_rate(timer_clk);
277
278	if (timer_is_v2())
279		clockevent_mxc.set_next_event = v2_set_next_event;
280
281	clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
282					clockevent_mxc.shift);
283	clockevent_mxc.max_delta_ns =
284			clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
285	clockevent_mxc.min_delta_ns =
286			clockevent_delta2ns(0xff, &clockevent_mxc);
287
288	clockevent_mxc.cpumask = cpumask_of(0);
289
290	clockevents_register_device(&clockevent_mxc);
291
292	return 0;
293}
294
295void __init mxc_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
296{
297	uint32_t tctl_val;
298
299	clk_enable(timer_clk);
300
301	timer_base = base;
302
303	/*
304	 * Initialise to a known state (all timers off, and timing reset)
305	 */
306
307	__raw_writel(0, timer_base + MXC_TCTL);
308	__raw_writel(0, timer_base + MXC_TPRER); /* see datasheet note */
309
310	if (timer_is_v2())
311		tctl_val = V2_TCTL_CLK_IPG | V2_TCTL_FRR | V2_TCTL_WAITEN | MXC_TCTL_TEN;
312	else
313		tctl_val = MX1_2_TCTL_FRR | MX1_2_TCTL_CLK_PCLK1 | MXC_TCTL_TEN;
314
315	__raw_writel(tctl_val, timer_base + MXC_TCTL);
316
317	/* init and register the timer to the framework */
318	mxc_clocksource_init(timer_clk);
319	mxc_clockevent_init(timer_clk);
320
321	/* Make irqs happen */
322	setup_irq(irq, &mxc_timer_irq);
323}
324