• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/plat-brcm/
1/*
2 *  Copyright (C) 1999 - 2003 ARM Limited
3 *  Copyright (C) 2000 Deep Blue Solutions Ltd
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/clockchips.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
24#include <linux/io.h>
25
26#include <plat/mpcore.h>
27#if defined(CONFIG_BUZZZ)
28#include <asm/buzzz.h>
29#endif  /*  CONFIG_BUZZZ */
30
31/*
32 * The ARM9 MPCORE Global Timer is a continously-running 64-bit timer,
33 * which is used both as a "clock source" and as a "clock event" -
34 * there is a banked per-cpu compare and reload registers that are
35 * used to generated either one-shot or periodic interrupts on the cpu
36 * that calls the mode_set function.
37 *
38 * NOTE: This code does not support dynamic change of the source clock
39 * frequency. The interrupt interval is only calculated once during
40 * initialization.
41 */
42
43/*
44 * Global Timer Registers
45 */
46#define	GTIMER_COUNT_LO		0x00	/* Lower 32 of 64 bits counter */
47#define	GTIMER_COUNT_HI		0x04	/* Higher 32 of 64 bits counter */
48#define	GTIMER_CTRL		0x08	/* Control (partially banked) */
49#define	GTIMER_CTRL_EN		(1<<0)	/* Timer enable bit */
50#define	GTIMER_CTRL_CMP_EN	(1<<1)	/* Comparator enable */
51#define	GTIMER_CTRL_IRQ_EN	(1<<2)	/* Interrupt enable */
52#define	GTIMER_CTRL_AUTO_EN	(1<<3)	/* Auto-increment enable */
53#define	GTIMER_INT_STAT		0x0C	/* Interrupt Status (banked) */
54#define	GTIMER_COMP_LO		0x10	/* Lower half comparator (banked) */
55#define	GTIMER_COMP_HI		0x14	/* Upper half comparator (banked) */
56#define	GTIMER_RELOAD		0x18	/* Auto-increment (banked) */
57
58#define	GTIMER_MIN_RANGE	30	/* Minimum wrap-around time in sec */
59
60/* Gobal variables */
61static void __iomem *gtimer_base;
62static u32 ticks_per_jiffy;
63
64extern void soc_watchdog(void);
65
66
67static cycle_t gptimer_count_read(struct clocksource *cs)
68{
69	u32 count_hi, count_ho, count_lo;
70	u64 count;
71
72	/* Avoid unexpected rollover with double-read of upper half */
73	do {
74		count_hi = readl( gtimer_base + GTIMER_COUNT_HI );
75		count_lo = readl( gtimer_base + GTIMER_COUNT_LO );
76		count_ho = readl( gtimer_base + GTIMER_COUNT_HI );
77	} while( count_hi != count_ho );
78
79	count = (u64) count_hi << 32 | count_lo ;
80	return count;
81}
82
83static struct clocksource clocksource_gptimer = {
84	.name		= "mpcore_gtimer",
85	.rating		= 300,
86	.read		= gptimer_count_read,
87	.mask		= CLOCKSOURCE_MASK(64),
88	.shift		= 20,
89	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
90};
91
92static void __init gptimer_clocksource_init(u32 freq)
93{
94	struct clocksource *cs = &clocksource_gptimer;
95
96	/* <freq> is timer clock in Hz */
97        clocksource_calc_mult_shift(cs, freq, GTIMER_MIN_RANGE);
98
99	clocksource_register(cs);
100}
101
102/*
103 * IRQ handler for the global timer
104 * This interrupt is banked per CPU so is handled identically
105 */
106static irqreturn_t gtimer_interrupt(int irq, void *dev_id)
107{
108	struct clock_event_device *evt = dev_id;
109
110	/* clear the interrupt */
111	writel(1, gtimer_base + GTIMER_INT_STAT);
112
113#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 2)
114	buzzz_kevt_log1(BUZZZ_KEVT_ID_GTIMER_EVENT, (u32)evt->event_handler);
115#endif	/* BUZZZ_KEVT_LVL */
116
117	evt->event_handler(evt);
118
119	soc_watchdog();
120
121	return IRQ_HANDLED;
122}
123
124static void gtimer_set_mode(
125	enum clock_event_mode mode,
126	struct clock_event_device *evt
127	)
128{
129	u32 ctrl, period;
130	u64 count;
131
132	/* Get current register with global enable and prescaler */
133	ctrl = readl( gtimer_base + GTIMER_CTRL );
134
135	/* Clear the mode-related bits */
136	ctrl &= ~( 	GTIMER_CTRL_CMP_EN |
137			GTIMER_CTRL_IRQ_EN |
138			GTIMER_CTRL_AUTO_EN);
139
140	switch (mode) {
141	case CLOCK_EVT_MODE_PERIODIC:
142		period = ticks_per_jiffy;
143		count = gptimer_count_read( NULL );
144		count += period ;
145		writel(ctrl, gtimer_base + GTIMER_CTRL);
146		writel(count & 0xffffffffUL, 	gtimer_base + GTIMER_COMP_LO);
147		writel(count >> 32, 		gtimer_base + GTIMER_COMP_HI);
148		writel(period, gtimer_base + GTIMER_RELOAD);
149		ctrl |= GTIMER_CTRL_CMP_EN |
150			GTIMER_CTRL_IRQ_EN |
151			GTIMER_CTRL_AUTO_EN ;
152		break;
153
154	case CLOCK_EVT_MODE_ONESHOT:
155		/* period set, and timer enabled in 'next_event' hook */
156		break;
157
158	case CLOCK_EVT_MODE_UNUSED:
159	case CLOCK_EVT_MODE_SHUTDOWN:
160	default:
161		break;
162	}
163	/* Apply the new mode */
164	writel(ctrl, gtimer_base + GTIMER_CTRL);
165}
166
167static int gtimer_set_next_event(
168	unsigned long next,
169	struct clock_event_device *evt
170	)
171{
172	u32 ctrl;
173	u64 count;
174
175#if defined(BUZZZ_KEVT_LVL) && (BUZZZ_KEVT_LVL >= 2)
176	buzzz_kevt_log1(BUZZZ_KEVT_ID_GTIMER_NEXT, (u32)next);
177#endif	/* BUZZZ_KEVT_LVL */
178
179	ctrl = readl(gtimer_base + GTIMER_CTRL);
180	count = gptimer_count_read( NULL );
181
182	ctrl &= ~GTIMER_CTRL_CMP_EN ;
183	writel(ctrl, gtimer_base + GTIMER_CTRL);
184
185	count += next ;
186
187	writel(count & 0xffffffffUL, 	gtimer_base + GTIMER_COMP_LO);
188	writel(count >> 32, 		gtimer_base + GTIMER_COMP_HI);
189
190	/* enable IRQ for the same cpu that loaded comparator */
191	ctrl |= GTIMER_CTRL_CMP_EN ;
192	ctrl |= GTIMER_CTRL_IRQ_EN ;
193
194	writel(ctrl, gtimer_base + GTIMER_CTRL);
195
196	return 0;
197}
198
199static struct clock_event_device gtimer_clockevent = {
200	.name		= "mpcore_gtimer",
201	.shift		= 20,
202	.features       = CLOCK_EVT_FEAT_PERIODIC,
203	.set_mode	= gtimer_set_mode,
204	.set_next_event	= gtimer_set_next_event,
205	.rating		= 300,
206	.cpumask	= cpu_all_mask,
207};
208
209static struct irqaction gtimer_irq = {
210	.name		= "mpcore_gtimer",
211	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
212	.handler	= gtimer_interrupt,
213	.dev_id		= &gtimer_clockevent,
214};
215
216static void __init gtimer_clockevents_init(u32 freq, unsigned timer_irq)
217{
218	struct clock_event_device *evt = &gtimer_clockevent;
219
220	evt->irq = timer_irq;
221        ticks_per_jiffy = DIV_ROUND_CLOSEST(freq, HZ);
222
223        clockevents_calc_mult_shift(evt, freq, GTIMER_MIN_RANGE);
224
225	evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
226	evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
227
228	/* Register the device to install handler before enabing IRQ */
229	clockevents_register_device(evt);
230	setup_irq(timer_irq, &gtimer_irq);
231}
232
233/*
234 * MPCORE Global Timer initialization function
235 */
236void __init mpcore_gtimer_init(
237	void __iomem *base,
238	unsigned long freq,
239	unsigned int timer_irq)
240{
241	u32 ctrl ;
242	u64 count;
243
244	gtimer_base = base;
245
246	printk(KERN_INFO "MPCORE Global Timer Clock %luHz\n",
247		(unsigned long) freq);
248
249	/* Prescaler = 0; let the Global Timer run at native PERIPHCLK rate */
250
251	ctrl = GTIMER_CTRL_EN;
252
253	/* Enable the free-running global counter */
254
255	writel(ctrl, gtimer_base + GTIMER_CTRL);
256
257	/* Self-test the timer is running */
258	count = gptimer_count_read(NULL);
259
260	/* Register as time source */
261	gptimer_clocksource_init(freq);
262
263	/* Register as system timer */
264	gtimer_clockevents_init(freq, timer_irq);
265
266	count = gptimer_count_read(NULL) - count ;
267	if( count == 0 )
268		printk(KERN_CRIT "MPCORE Global Timer Dead!!\n");
269}
270