Blame view

arch/arm/mach-omap1/time.c 7.07 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
3b59b6beb   Tony Lindgren   [PATCH] ARM: 2800...
2
   * linux/arch/arm/mach-omap1/time.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
   *
   * OMAP Timers
   *
   * Copyright (C) 2004 Nokia Corporation
b3402cf50   Tony Lindgren   [PATCH] ARM: 2771...
7
   * Partial timer rewrite and additional dynamic tick timer support by
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   * Tony Lindgen <tony@atomide.com> and
   * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
   *
   * MPU timer code based on the older MPU timer code for OMAP
   * Copyright (C) 2000 RidgeRun, Inc.
   * Author: Greg Lonnon <glonnon@ridgerun.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
   * Free Software Foundation; either version 2 of the License, or (at your
   * option) any later version.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
   * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * You should have received a copy of the  GNU General Public License along
   * with this program; if not, write  to the Free Software Foundation, Inc.,
   * 675 Mass Ave, Cambridge, MA 02139, USA.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  #include <linux/spinlock.h>
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
40
41
42
43
  #include <linux/clk.h>
  #include <linux/err.h>
  #include <linux/clocksource.h>
  #include <linux/clockchips.h>
fced80c73   Russell King   [ARM] Convert asm...
44
  #include <linux/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
  
  #include <asm/system.h>
a09e64fbc   Russell King   [ARM] Move includ...
47
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
  #include <asm/leds.h>
  #include <asm/irq.h>
f376ea178   Tony Lindgren   omap1: Fix sched_...
50
  #include <asm/sched_clock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
  #include <asm/mach/irq.h>
  #include <asm/mach/time.h>
4e65331c6   Tony Lindgren   ARM: 7159/1: OMAP...
53
  #include "common.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

05b5ca9b1   Tony Lindgren   omap1: Fix bootin...
55
  #ifdef CONFIG_OMAP_MPU_TIMER
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
  #define OMAP_MPU_TIMER_BASE		OMAP_MPU_TIMER1_BASE
  #define OMAP_MPU_TIMER_OFFSET		0x100
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
  typedef struct {
  	u32 cntl;			/* CNTL_TIMER, R/W */
  	u32 load_tim;			/* LOAD_TIM,   W */
  	u32 read_tim;			/* READ_TIM,   R */
  } omap_mpu_timer_regs_t;
941132606   Tony Lindgren   OMAP: Remove OMAP...
63
  #define omap_mpu_timer_base(n)							\
111c7751e   Russell King   ARM: omap1: conve...
64
  ((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE +	\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  				 (n)*OMAP_MPU_TIMER_OFFSET))
f376ea178   Tony Lindgren   omap1: Fix sched_...
66
  static inline unsigned long notrace omap_mpu_timer_read(int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
111c7751e   Russell King   ARM: omap1: conve...
68
69
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
  	return readl(&timer->read_tim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
71
  static inline void omap_mpu_set_autoreset(int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
  {
111c7751e   Russell King   ARM: omap1: conve...
73
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74

111c7751e   Russell King   ARM: omap1: conve...
75
  	writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
77
  static inline void omap_mpu_remove_autoreset(int nr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  {
111c7751e   Russell King   ARM: omap1: conve...
79
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

111c7751e   Russell King   ARM: omap1: conve...
81
  	writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
83
84
85
  static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
  					int autoreset)
  {
111c7751e   Russell King   ARM: omap1: conve...
86
87
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
  	unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
88

111c7751e   Russell King   ARM: omap1: conve...
89
90
  	if (autoreset)
  		timerflags |= MPU_TIMER_AR;
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
91

111c7751e   Russell King   ARM: omap1: conve...
92
  	writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
93
  	udelay(1);
111c7751e   Russell King   ARM: omap1: conve...
94
  	writel(load_val, &timer->load_tim);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
95
          udelay(1);
111c7751e   Russell King   ARM: omap1: conve...
96
  	writel(timerflags, &timer->cntl);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
97
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98

06cad098d   Kevin Hilman   ARM: OMAP: Fix cl...
99
100
  static inline void omap_mpu_timer_stop(int nr)
  {
111c7751e   Russell King   ARM: omap1: conve...
101
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
06cad098d   Kevin Hilman   ARM: OMAP: Fix cl...
102

111c7751e   Russell King   ARM: omap1: conve...
103
  	writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
06cad098d   Kevin Hilman   ARM: OMAP: Fix cl...
104
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  /*
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
106
107
108
   * ---------------------------------------------------------------------------
   * MPU timer 1 ... count down to zero, interrupt, reload
   * ---------------------------------------------------------------------------
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
   */
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
110
  static int omap_mpu_set_next_event(unsigned long cycles,
06cad098d   Kevin Hilman   ARM: OMAP: Fix cl...
111
  				   struct clock_event_device *evt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
113
114
115
  	omap_mpu_timer_start(0, cycles, 0);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
117
118
119
120
121
122
123
124
  static void omap_mpu_set_mode(enum clock_event_mode mode,
  			      struct clock_event_device *evt)
  {
  	switch (mode) {
  	case CLOCK_EVT_MODE_PERIODIC:
  		omap_mpu_set_autoreset(0);
  		break;
  	case CLOCK_EVT_MODE_ONESHOT:
06cad098d   Kevin Hilman   ARM: OMAP: Fix cl...
125
  		omap_mpu_timer_stop(0);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
126
127
128
129
  		omap_mpu_remove_autoreset(0);
  		break;
  	case CLOCK_EVT_MODE_UNUSED:
  	case CLOCK_EVT_MODE_SHUTDOWN:
18de5bc4c   Thomas Gleixner   clockevents: fix ...
130
  	case CLOCK_EVT_MODE_RESUME:
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
131
132
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
134
135
  static struct clock_event_device clockevent_mpu_timer1 = {
  	.name		= "mpu_timer1",
c6b349ed8   Will Newton   ARM: OMAP1: Fix t...
136
  	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
137
138
139
140
141
142
  	.shift		= 32,
  	.set_next_event	= omap_mpu_set_next_event,
  	.set_mode	= omap_mpu_set_mode,
  };
  
  static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  {
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
144
  	struct clock_event_device *evt = &clockevent_mpu_timer1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145

075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
146
  	evt->event_handler(evt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
  
  	return IRQ_HANDLED;
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
150
151
  static struct irqaction omap_mpu_timer1_irq = {
  	.name		= "mpu_timer1",
b30fabada   Bernhard Walle   Add IRQF_IRQPOLL ...
152
  	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
153
  	.handler	= omap_mpu_timer1_interrupt,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  };
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
155
156
  static __init void omap_init_mpu_timer(unsigned long rate)
  {
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
157
158
159
160
161
162
163
164
165
  	setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
  	omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
  
  	clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
  					    clockevent_mpu_timer1.shift);
  	clockevent_mpu_timer1.max_delta_ns =
  		clockevent_delta2ns(-1, &clockevent_mpu_timer1);
  	clockevent_mpu_timer1.min_delta_ns =
  		clockevent_delta2ns(1, &clockevent_mpu_timer1);
320ab2b0b   Rusty Russell   cpumask: convert ...
166
  	clockevent_mpu_timer1.cpumask = cpumask_of(0);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
167
168
169
170
171
172
173
174
175
  	clockevents_register_device(&clockevent_mpu_timer1);
  }
  
  
  /*
   * ---------------------------------------------------------------------------
   * MPU timer 2 ... free running 32-bit clock source and scheduler clock
   * ---------------------------------------------------------------------------
   */
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
176
  static u32 notrace omap_mpu_read_sched_clock(void)
f376ea178   Tony Lindgren   omap1: Fix sched_...
177
  {
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
178
  	return ~omap_mpu_timer_read(1);
f376ea178   Tony Lindgren   omap1: Fix sched_...
179
  }
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
180
181
  static void __init omap_init_clocksource(unsigned long rate)
  {
933e54a53   Russell King   clocksource: conv...
182
  	omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
183
184
185
  	static char err[] __initdata = KERN_ERR
  			"%s: can't register clocksource!
  ";
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
186
  	omap_mpu_timer_start(1, ~0, 1);
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
187
  	setup_sched_clock(omap_mpu_read_sched_clock, 32, rate);
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
188

933e54a53   Russell King   clocksource: conv...
189
190
191
  	if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
  			300, 32, clocksource_mmio_readl_down))
  		printk(err, "mpu_timer2");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  }
05b5ca9b1   Tony Lindgren   omap1: Fix bootin...
193
  static void __init omap_mpu_timer_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  {
075192ae8   Kevin Hilman   [ARM] 4262/1: OMA...
195
196
197
198
199
200
201
202
203
204
205
206
207
  	struct clk	*ck_ref = clk_get(NULL, "ck_ref");
  	unsigned long	rate;
  
  	BUG_ON(IS_ERR(ck_ref));
  
  	rate = clk_get_rate(ck_ref);
  	clk_put(ck_ref);
  
  	/* PTV = 0 */
  	rate /= 2;
  
  	omap_init_mpu_timer(rate);
  	omap_init_clocksource(rate);
05b5ca9b1   Tony Lindgren   omap1: Fix bootin...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  }
  
  #else
  static inline void omap_mpu_timer_init(void)
  {
  	pr_err("Bogus timer, should not happen
  ");
  }
  #endif	/* CONFIG_OMAP_MPU_TIMER */
  
  static inline int omap_32k_timer_usable(void)
  {
  	int res = false;
  
  	if (cpu_is_omap730() || cpu_is_omap15xx())
  		return res;
  
  #ifdef CONFIG_OMAP_32K_TIMER
  	res = omap_32k_timer_init();
  #endif
  
  	return res;
  }
  
  /*
   * ---------------------------------------------------------------------------
   * Timer initialization
   * ---------------------------------------------------------------------------
   */
e74984e46   Tony Lindgren   omap: Set separat...
237
  static void __init omap1_timer_init(void)
05b5ca9b1   Tony Lindgren   omap1: Fix bootin...
238
  {
2f0778afa   Marc Zyngier   ARM: 7205/2: sche...
239
  	if (!omap_32k_timer_usable())
05b5ca9b1   Tony Lindgren   omap1: Fix bootin...
240
  		omap_mpu_timer_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
  }
e74984e46   Tony Lindgren   omap: Set separat...
242
243
  struct sys_timer omap1_timer = {
  	.init		= omap1_timer_init,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
  };