xref: /openbmc/linux/arch/microblaze/kernel/timer.c (revision 0d456bad)
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 <linux/bug.h>
26 #include <asm/cpuinfo.h>
27 #include <asm/setup.h>
28 #include <asm/prom.h>
29 #include <asm/irq.h>
30 #include <linux/cnt32_to_63.h>
31 
32 #ifdef CONFIG_SELFMOD_TIMER
33 #include <asm/selfmod.h>
34 #define TIMER_BASE	BARRIER_BASE_ADDR
35 #else
36 static unsigned int timer_baseaddr;
37 #define TIMER_BASE	timer_baseaddr
38 #endif
39 
40 static unsigned int freq_div_hz;
41 static unsigned int timer_clock_freq;
42 
43 #define TCSR0	(0x00)
44 #define TLR0	(0x04)
45 #define TCR0	(0x08)
46 #define TCSR1	(0x10)
47 #define TLR1	(0x14)
48 #define TCR1	(0x18)
49 
50 #define TCSR_MDT	(1<<0)
51 #define TCSR_UDT	(1<<1)
52 #define TCSR_GENT	(1<<2)
53 #define TCSR_CAPT	(1<<3)
54 #define TCSR_ARHT	(1<<4)
55 #define TCSR_LOAD	(1<<5)
56 #define TCSR_ENIT	(1<<6)
57 #define TCSR_ENT	(1<<7)
58 #define TCSR_TINT	(1<<8)
59 #define TCSR_PWMA	(1<<9)
60 #define TCSR_ENALL	(1<<10)
61 
62 static inline void microblaze_timer0_stop(void)
63 {
64 	out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT);
65 }
66 
67 static inline void microblaze_timer0_start_periodic(unsigned long load_val)
68 {
69 	if (!load_val)
70 		load_val = 1;
71 	out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
72 
73 	/* load the initial value */
74 	out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
75 
76 	/* see timer data sheet for detail
77 	 * !ENALL - don't enable 'em all
78 	 * !PWMA - disable pwm
79 	 * TINT - clear interrupt status
80 	 * ENT- enable timer itself
81 	 * ENIT - enable interrupt
82 	 * !LOAD - clear the bit to let go
83 	 * ARHT - auto reload
84 	 * !CAPT - no external trigger
85 	 * !GENT - no external signal
86 	 * UDT - set the timer as down counter
87 	 * !MDT0 - generate mode
88 	 */
89 	out_be32(TIMER_BASE + TCSR0,
90 			TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
91 }
92 
93 static inline void microblaze_timer0_start_oneshot(unsigned long load_val)
94 {
95 	if (!load_val)
96 		load_val = 1;
97 	out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */
98 
99 	/* load the initial value */
100 	out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
101 
102 	out_be32(TIMER_BASE + TCSR0,
103 			TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
104 }
105 
106 static int microblaze_timer_set_next_event(unsigned long delta,
107 					struct clock_event_device *dev)
108 {
109 	pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
110 	microblaze_timer0_start_oneshot(delta);
111 	return 0;
112 }
113 
114 static void microblaze_timer_set_mode(enum clock_event_mode mode,
115 				struct clock_event_device *evt)
116 {
117 	switch (mode) {
118 	case CLOCK_EVT_MODE_PERIODIC:
119 		pr_info("%s: periodic\n", __func__);
120 		microblaze_timer0_start_periodic(freq_div_hz);
121 		break;
122 	case CLOCK_EVT_MODE_ONESHOT:
123 		pr_info("%s: oneshot\n", __func__);
124 		break;
125 	case CLOCK_EVT_MODE_UNUSED:
126 		pr_info("%s: unused\n", __func__);
127 		break;
128 	case CLOCK_EVT_MODE_SHUTDOWN:
129 		pr_info("%s: shutdown\n", __func__);
130 		microblaze_timer0_stop();
131 		break;
132 	case CLOCK_EVT_MODE_RESUME:
133 		pr_info("%s: resume\n", __func__);
134 		break;
135 	}
136 }
137 
138 static struct clock_event_device clockevent_microblaze_timer = {
139 	.name		= "microblaze_clockevent",
140 	.features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
141 	.shift		= 8,
142 	.rating		= 300,
143 	.set_next_event	= microblaze_timer_set_next_event,
144 	.set_mode	= microblaze_timer_set_mode,
145 };
146 
147 static inline void timer_ack(void)
148 {
149 	out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0));
150 }
151 
152 static irqreturn_t timer_interrupt(int irq, void *dev_id)
153 {
154 	struct clock_event_device *evt = &clockevent_microblaze_timer;
155 #ifdef CONFIG_HEART_BEAT
156 	heartbeat();
157 #endif
158 	timer_ack();
159 	evt->event_handler(evt);
160 	return IRQ_HANDLED;
161 }
162 
163 static struct irqaction timer_irqaction = {
164 	.handler = timer_interrupt,
165 	.flags = IRQF_DISABLED | IRQF_TIMER,
166 	.name = "timer",
167 	.dev_id = &clockevent_microblaze_timer,
168 };
169 
170 static __init void microblaze_clockevent_init(void)
171 {
172 	clockevent_microblaze_timer.mult =
173 		div_sc(timer_clock_freq, NSEC_PER_SEC,
174 				clockevent_microblaze_timer.shift);
175 	clockevent_microblaze_timer.max_delta_ns =
176 		clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
177 	clockevent_microblaze_timer.min_delta_ns =
178 		clockevent_delta2ns(1, &clockevent_microblaze_timer);
179 	clockevent_microblaze_timer.cpumask = cpumask_of(0);
180 	clockevents_register_device(&clockevent_microblaze_timer);
181 }
182 
183 static cycle_t microblaze_read(struct clocksource *cs)
184 {
185 	/* reading actual value of timer 1 */
186 	return (cycle_t) (in_be32(TIMER_BASE + TCR1));
187 }
188 
189 static struct timecounter microblaze_tc = {
190 	.cc = NULL,
191 };
192 
193 static cycle_t microblaze_cc_read(const struct cyclecounter *cc)
194 {
195 	return microblaze_read(NULL);
196 }
197 
198 static struct cyclecounter microblaze_cc = {
199 	.read = microblaze_cc_read,
200 	.mask = CLOCKSOURCE_MASK(32),
201 	.shift = 8,
202 };
203 
204 static int __init init_microblaze_timecounter(void)
205 {
206 	microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
207 				microblaze_cc.shift);
208 
209 	timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
210 
211 	return 0;
212 }
213 
214 static struct clocksource clocksource_microblaze = {
215 	.name		= "microblaze_clocksource",
216 	.rating		= 300,
217 	.read		= microblaze_read,
218 	.mask		= CLOCKSOURCE_MASK(32),
219 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
220 };
221 
222 static int __init microblaze_clocksource_init(void)
223 {
224 	if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq))
225 		panic("failed to register clocksource");
226 
227 	/* stop timer1 */
228 	out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
229 	/* start timer1 - up counting without interrupt */
230 	out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
231 
232 	/* register timecounter - for ftrace support */
233 	init_microblaze_timecounter();
234 	return 0;
235 }
236 
237 /*
238  * We have to protect accesses before timer initialization
239  * and return 0 for sched_clock function below.
240  */
241 static int timer_initialized;
242 
243 void __init time_init(void)
244 {
245 	u32 irq;
246 	u32 timer_num = 1;
247 	struct device_node *timer = NULL;
248 	const void *prop;
249 #ifdef CONFIG_SELFMOD_TIMER
250 	unsigned int timer_baseaddr = 0;
251 	int arr_func[] = {
252 				(int)&microblaze_read,
253 				(int)&timer_interrupt,
254 				(int)&microblaze_clocksource_init,
255 				(int)&microblaze_timer_set_mode,
256 				(int)&microblaze_timer_set_next_event,
257 				0
258 			};
259 #endif
260 	prop = of_get_property(of_chosen, "system-timer", NULL);
261 	if (prop)
262 		timer = of_find_node_by_phandle(be32_to_cpup(prop));
263 	else
264 		pr_info("No chosen timer found, using default\n");
265 
266 	if (!timer)
267 		timer = of_find_compatible_node(NULL, NULL,
268 						"xlnx,xps-timer-1.00.a");
269 	BUG_ON(!timer);
270 
271 	timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
272 	timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
273 	irq = irq_of_parse_and_map(timer, 0);
274 	timer_num = be32_to_cpup(of_get_property(timer,
275 						"xlnx,one-timer-only", NULL));
276 	if (timer_num) {
277 		pr_emerg("Please   enable two timers in HW\n");
278 		BUG();
279 	}
280 
281 #ifdef CONFIG_SELFMOD_TIMER
282 	selfmod_function((int *) arr_func, timer_baseaddr);
283 #endif
284 	pr_info("%s #0 at 0x%08x, irq=%d\n",
285 		timer->name, timer_baseaddr, irq);
286 
287 	/* If there is clock-frequency property than use it */
288 	prop = of_get_property(timer, "clock-frequency", NULL);
289 	if (prop)
290 		timer_clock_freq = be32_to_cpup(prop);
291 	else
292 		timer_clock_freq = cpuinfo.cpu_clock_freq;
293 
294 	freq_div_hz = timer_clock_freq / HZ;
295 
296 	setup_irq(irq, &timer_irqaction);
297 #ifdef CONFIG_HEART_BEAT
298 	setup_heartbeat();
299 #endif
300 	microblaze_clocksource_init();
301 	microblaze_clockevent_init();
302 	timer_initialized = 1;
303 }
304 
305 unsigned long long notrace sched_clock(void)
306 {
307 	if (timer_initialized) {
308 		struct clocksource *cs = &clocksource_microblaze;
309 
310 		cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX;
311 		return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
312 	}
313 	return 0;
314 }
315