Merge branch 'bjorn.button' into release
[linux-2.6] / arch / microblaze / kernel / timer.c
1 /*
2  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3  * Copyright (C) 2007-2009 PetaLogix
4  * Copyright (C) 2006 Atmark Techno, Inc.
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License. See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10
11 #include <linux/init.h>
12 #include <linux/kernel.h>
13 #include <linux/param.h>
14 #include <linux/interrupt.h>
15 #include <linux/profile.h>
16 #include <linux/irq.h>
17 #include <linux/delay.h>
18 #include <linux/sched.h>
19 #include <linux/spinlock.h>
20 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/clocksource.h>
23 #include <linux/clockchips.h>
24 #include <linux/io.h>
25 #include <asm/cpuinfo.h>
26 #include <asm/setup.h>
27 #include <asm/prom.h>
28 #include <asm/irq.h>
29 #include <asm/system.h>
30
31 #ifdef CONFIG_SELFMOD_TIMER
32 #include <asm/selfmod.h>
33 #define TIMER_BASE      BARRIER_BASE_ADDR
34 #else
35 static unsigned int timer_baseaddr;
36 #define TIMER_BASE      timer_baseaddr
37 #endif
38
39 #define TCSR0   (0x00)
40 #define TLR0    (0x04)
41 #define TCR0    (0x08)
42 #define TCSR1   (0x10)
43 #define TLR1    (0x14)
44 #define TCR1    (0x18)
45
46 #define TCSR_MDT        (1<<0)
47 #define TCSR_UDT        (1<<1)
48 #define TCSR_GENT       (1<<2)
49 #define TCSR_CAPT       (1<<3)
50 #define TCSR_ARHT       (1<<4)
51 #define TCSR_LOAD       (1<<5)
52 #define TCSR_ENIT       (1<<6)
53 #define TCSR_ENT        (1<<7)
54 #define TCSR_TINT       (1<<8)
55 #define TCSR_PWMA       (1<<9)
56 #define TCSR_ENALL      (1<<10)
57
58 static inline void microblaze_timer0_stop(void)
59 {
60         out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT);
61 }
62
63 static inline void microblaze_timer0_start_periodic(unsigned long load_val)
64 {
65         if (!load_val)
66                 load_val = 1;
67         out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
68
69         /* load the initial value */
70         out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
71
72         /* see timer data sheet for detail
73          * !ENALL - don't enable 'em all
74          * !PWMA - disable pwm
75          * TINT - clear interrupt status
76          * ENT- enable timer itself
77          * EINT - enable interrupt
78          * !LOAD - clear the bit to let go
79          * ARHT - auto reload
80          * !CAPT - no external trigger
81          * !GENT - no external signal
82          * UDT - set the timer as down counter
83          * !MDT0 - generate mode
84          */
85         out_be32(TIMER_BASE + TCSR0,
86                         TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
87 }
88
89 static inline void microblaze_timer0_start_oneshot(unsigned long load_val)
90 {
91         if (!load_val)
92                 load_val = 1;
93         out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
94
95         /* load the initial value */
96         out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
97
98         out_be32(TIMER_BASE + TCSR0,
99                         TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
100 }
101
102 static int microblaze_timer_set_next_event(unsigned long delta,
103                                         struct clock_event_device *dev)
104 {
105         pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
106         microblaze_timer0_start_oneshot(delta);
107         return 0;
108 }
109
110 static void microblaze_timer_set_mode(enum clock_event_mode mode,
111                                 struct clock_event_device *evt)
112 {
113         switch (mode) {
114         case CLOCK_EVT_MODE_PERIODIC:
115                 printk(KERN_INFO "%s: periodic\n", __func__);
116                 microblaze_timer0_start_periodic(cpuinfo.freq_div_hz);
117                 break;
118         case CLOCK_EVT_MODE_ONESHOT:
119                 printk(KERN_INFO "%s: oneshot\n", __func__);
120                 break;
121         case CLOCK_EVT_MODE_UNUSED:
122                 printk(KERN_INFO "%s: unused\n", __func__);
123                 break;
124         case CLOCK_EVT_MODE_SHUTDOWN:
125                 printk(KERN_INFO "%s: shutdown\n", __func__);
126                 microblaze_timer0_stop();
127                 break;
128         case CLOCK_EVT_MODE_RESUME:
129                 printk(KERN_INFO "%s: resume\n", __func__);
130                 break;
131         }
132 }
133
134 static struct clock_event_device clockevent_microblaze_timer = {
135         .name           = "microblaze_clockevent",
136         .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
137         .shift          = 24,
138         .rating         = 300,
139         .set_next_event = microblaze_timer_set_next_event,
140         .set_mode       = microblaze_timer_set_mode,
141 };
142
143 static inline void timer_ack(void)
144 {
145         out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0));
146 }
147
148 static irqreturn_t timer_interrupt(int irq, void *dev_id)
149 {
150         struct clock_event_device *evt = &clockevent_microblaze_timer;
151 #ifdef CONFIG_HEART_BEAT
152         heartbeat();
153 #endif
154         timer_ack();
155         evt->event_handler(evt);
156         return IRQ_HANDLED;
157 }
158
159 static struct irqaction timer_irqaction = {
160         .handler = timer_interrupt,
161         .flags = IRQF_DISABLED | IRQF_TIMER,
162         .name = "timer",
163         .dev_id = &clockevent_microblaze_timer,
164 };
165
166 static __init void microblaze_clockevent_init(void)
167 {
168         clockevent_microblaze_timer.mult =
169                 div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
170                                 clockevent_microblaze_timer.shift);
171         clockevent_microblaze_timer.max_delta_ns =
172                 clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
173         clockevent_microblaze_timer.min_delta_ns =
174                 clockevent_delta2ns(1, &clockevent_microblaze_timer);
175         clockevent_microblaze_timer.cpumask = cpumask_of(0);
176         clockevents_register_device(&clockevent_microblaze_timer);
177 }
178
179 static cycle_t microblaze_read(void)
180 {
181         /* reading actual value of timer 1 */
182         return (cycle_t) (in_be32(TIMER_BASE + TCR1));
183 }
184
185 static struct clocksource clocksource_microblaze = {
186         .name           = "microblaze_clocksource",
187         .rating         = 300,
188         .read           = microblaze_read,
189         .mask           = CLOCKSOURCE_MASK(32),
190         .shift          = 24, /* I can shift it */
191         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
192 };
193
194 static int __init microblaze_clocksource_init(void)
195 {
196         clocksource_microblaze.mult =
197                         clocksource_hz2mult(cpuinfo.cpu_clock_freq,
198                                                 clocksource_microblaze.shift);
199         if (clocksource_register(&clocksource_microblaze))
200                 panic("failed to register clocksource");
201
202         /* stop timer1 */
203         out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
204         /* start timer1 - up counting without interrupt */
205         out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
206         return 0;
207 }
208
209 void __init time_init(void)
210 {
211         u32 irq, i = 0;
212         u32 timer_num = 1;
213         struct device_node *timer = NULL;
214 #ifdef CONFIG_SELFMOD_TIMER
215         unsigned int timer_baseaddr = 0;
216         int arr_func[] = {
217                                 (int)&microblaze_read,
218                                 (int)&timer_interrupt,
219                                 (int)&microblaze_clocksource_init,
220                                 (int)&microblaze_timer_set_mode,
221                                 (int)&microblaze_timer_set_next_event,
222                                 0
223                         };
224 #endif
225         char *timer_list[] = {
226                                 "xlnx,xps-timer-1.00.a",
227                                 "xlnx,opb-timer-1.00.b",
228                                 "xlnx,opb-timer-1.00.a",
229                                 NULL
230                         };
231
232         for (i = 0; timer_list[i] != NULL; i++) {
233                 timer = of_find_compatible_node(NULL, NULL, timer_list[i]);
234                 if (timer)
235                         break;
236         }
237
238         timer_baseaddr = *(int *) of_get_property(timer, "reg", NULL);
239         timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
240         irq = *(int *) of_get_property(timer, "interrupts", NULL);
241         timer_num =
242                 *(int *) of_get_property(timer, "xlnx,one-timer-only", NULL);
243         if (timer_num) {
244                 printk(KERN_EMERG "Please enable two timers in HW\n");
245                 BUG();
246         }
247
248 #ifdef CONFIG_SELFMOD_TIMER
249         selfmod_function((int *) arr_func, timer_baseaddr);
250 #endif
251         printk(KERN_INFO "%s #0 at 0x%08x, irq=%d\n",
252                 timer_list[i], timer_baseaddr, irq);
253
254         cpuinfo.freq_div_hz = cpuinfo.cpu_clock_freq / HZ;
255
256         setup_irq(irq, &timer_irqaction);
257 #ifdef CONFIG_HEART_BEAT
258         setup_heartbeat();
259 #endif
260         microblaze_clocksource_init();
261         microblaze_clockevent_init();
262 }