xref: /NextBSD/sys/arm/cavium/cns11xx/timer.c (revision 95f7c2f56c7268d6ed9c2a56d357aeeac260363b)
1 /*-
2  * Copyright (c) 2009 Yohanes Nugroho <yohanes@gmail.com>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/bus.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
34 #include <sys/malloc.h>
35 #include <sys/rman.h>
36 #include <sys/timetc.h>
37 #include <sys/watchdog.h>
38 #include <machine/bus.h>
39 #include <machine/cpu.h>
40 #include <machine/intr.h>
41 
42 #include "econa_reg.h"
43 #include "econa_var.h"
44 
45 #define	INITIAL_TIMECOUNTER	(0xffffffff)
46 
47 static int timers_initialized = 0;
48 
49 #define	HZ	100
50 
51 extern unsigned int CPU_clock;
52 extern unsigned int AHB_clock;
53 extern unsigned int APB_clock;
54 
55 static unsigned long timer_counter = 0;
56 
57 struct ec_timer_softc {
58 	struct resource	*	timer_res[3];
59 	bus_space_tag_t		timer_bst;
60 	bus_space_handle_t	timer_bsh;
61 	struct mtx		timer_mtx;
62 };
63 
64 static struct resource_spec ec_timer_spec[] = {
65 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
66 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
67 	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
68 	{ -1, 0 }
69 };
70 
71 static unsigned ec_timer_get_timecount(struct timecounter *);
72 
73 static struct timecounter ec_timecounter = {
74 	.tc_get_timecount = ec_timer_get_timecount,
75 	.tc_name = "CPU Timer",
76 	/* This is assigned on the fly in the init sequence */
77 	.tc_frequency = 0,
78 	.tc_counter_mask = ~0u,
79 	.tc_quality = 1000,
80 };
81 
82 static struct ec_timer_softc *timer_softc = NULL;
83 
84 static inline
write_4(unsigned int val,unsigned int addr)85 void write_4(unsigned int val, unsigned int addr)
86 {
87 	bus_space_write_4(timer_softc->timer_bst,
88 			  timer_softc->timer_bsh, addr, val);
89 
90 }
91 
92 static inline
read_4(unsigned int addr)93 unsigned int read_4(unsigned int addr)
94 {
95 
96 	return bus_space_read_4(timer_softc->timer_bst,
97 	    timer_softc->timer_bsh, addr);
98 }
99 
100 #define	uSECS_PER_TICK	(1000000 / APB_clock)
101 #define	TICKS2USECS(x)	((x) * uSECS_PER_TICK)
102 
103 static unsigned
read_timer_counter_noint(void)104 read_timer_counter_noint(void)
105 {
106 
107 	arm_mask_irq(0);
108 	unsigned int v = read_4(TIMER_TM1_COUNTER_REG);
109 	arm_unmask_irq(0);
110 	return v;
111 }
112 
113 void
DELAY(int usec)114 DELAY(int usec)
115 {
116 	uint32_t val, val_temp;
117 	int nticks;
118 
119 	if (!timers_initialized) {
120 		for (; usec > 0; usec--)
121 			for (val = 100; val > 0; val--)
122 				;
123 		return;
124 	}
125 
126 	val = read_timer_counter_noint();
127 	nticks = (((APB_clock / 1000) * usec) / 1000) + 100;
128 
129 	while (nticks > 0) {
130 		val_temp = read_timer_counter_noint();
131 		if (val > val_temp)
132 			nticks -= (val - val_temp);
133 		else
134 			nticks -= (val + (timer_counter - val_temp));
135 
136 		val = val_temp;
137 	}
138 
139 }
140 
141 /*
142  * Setup timer
143  */
144 static inline void
setup_timer(unsigned int counter_value)145 setup_timer(unsigned int counter_value)
146 {
147 	unsigned int control_value;
148 	unsigned int mask_value;
149 
150 	control_value = read_4(TIMER_TM_CR_REG);
151 
152 	mask_value = read_4(TIMER_TM_INTR_MASK_REG);
153 	write_4(counter_value, TIMER_TM1_COUNTER_REG);
154 	write_4(counter_value, TIMER_TM1_LOAD_REG);
155 	write_4(0, TIMER_TM1_MATCH1_REG);
156 	write_4(0,TIMER_TM1_MATCH2_REG);
157 
158 	control_value &= ~(TIMER1_CLOCK_SOURCE);
159 	control_value |= TIMER1_UP_DOWN_COUNT;
160 
161 	write_4(0, TIMER_TM2_COUNTER_REG);
162 	write_4(0, TIMER_TM2_LOAD_REG);
163 	write_4(~0u, TIMER_TM2_MATCH1_REG);
164 	write_4(~0u,TIMER_TM2_MATCH2_REG);
165 
166 	control_value &= ~(TIMER2_CLOCK_SOURCE);
167 	control_value &= ~(TIMER2_UP_DOWN_COUNT);
168 
169 	mask_value &= ~(63);
170 
171 	write_4(control_value, TIMER_TM_CR_REG);
172 	write_4(mask_value, TIMER_TM_INTR_MASK_REG);
173 }
174 
175 /*
176  * Enable timer
177  */
178 static inline void
timer_enable(void)179 timer_enable(void)
180 {
181 	unsigned int control_value;
182 
183 	control_value = read_4(TIMER_TM_CR_REG);
184 
185 	control_value |= TIMER1_OVERFLOW_ENABLE;
186 	control_value |= TIMER1_ENABLE;
187 	control_value |= TIMER2_OVERFLOW_ENABLE;
188 	control_value |= TIMER2_ENABLE;
189 
190 	write_4(control_value, TIMER_TM_CR_REG);
191 }
192 
193 static inline unsigned int
read_second_timer_counter(void)194 read_second_timer_counter(void)
195 {
196 
197 	return read_4(TIMER_TM2_COUNTER_REG);
198 }
199 
200 /*
201  * Get timer interrupt status
202  */
203 static inline unsigned int
read_timer_interrupt_status(void)204 read_timer_interrupt_status(void)
205 {
206 
207 	return read_4(TIMER_TM_INTR_STATUS_REG);
208 }
209 
210 /*
211  * Clear timer interrupt status
212  */
213 static inline void
clear_timer_interrupt_status(unsigned int irq)214 clear_timer_interrupt_status(unsigned int irq)
215 {
216 	unsigned int interrupt_status;
217 
218 	interrupt_status =   read_4(TIMER_TM_INTR_STATUS_REG);
219 	if (irq == 0) {
220 		if (interrupt_status & (TIMER1_MATCH1_INTR))
221 			interrupt_status &= ~(TIMER1_MATCH1_INTR);
222 		if (interrupt_status & (TIMER1_MATCH2_INTR))
223 			interrupt_status &= ~(TIMER1_MATCH2_INTR);
224 		if (interrupt_status & (TIMER1_OVERFLOW_INTR))
225 			interrupt_status &= ~(TIMER1_OVERFLOW_INTR);
226 	}
227 	if (irq == 1) {
228 		if (interrupt_status & (TIMER2_MATCH1_INTR))
229 			interrupt_status &= ~(TIMER2_MATCH1_INTR);
230 		if (interrupt_status & (TIMER2_MATCH2_INTR))
231 			interrupt_status &= ~(TIMER2_MATCH2_INTR);
232 		if (interrupt_status & (TIMER2_OVERFLOW_INTR))
233 			interrupt_status &= ~(TIMER2_OVERFLOW_INTR);
234 	}
235 
236 	write_4(interrupt_status, TIMER_TM_INTR_STATUS_REG);
237 }
238 
239 static unsigned
ec_timer_get_timecount(struct timecounter * a)240 ec_timer_get_timecount(struct timecounter *a)
241 {
242 	unsigned int ticks1;
243 	arm_mask_irq(1);
244 	ticks1 = read_second_timer_counter();
245 	arm_unmask_irq(1);
246 	return ticks1;
247 }
248 
249 /*
250  * Setup timer
251  */
252 static inline void
do_setup_timer(void)253 do_setup_timer(void)
254 {
255 
256 	timer_counter = APB_clock/HZ;
257 	/*
258 	 * setup timer-related values
259 	 */
260 	setup_timer(timer_counter);
261 }
262 
263 void
cpu_initclocks(void)264 cpu_initclocks(void)
265 {
266 
267 	ec_timecounter.tc_frequency = APB_clock;
268 	tc_init(&ec_timecounter);
269 	timer_enable();
270 	timers_initialized = 1;
271 }
272 
273 void
cpu_startprofclock(void)274 cpu_startprofclock(void)
275 {
276 
277 }
278 
279 void
cpu_stopprofclock(void)280 cpu_stopprofclock(void)
281 {
282 
283 }
284 
285 static int
ec_timer_probe(device_t dev)286 ec_timer_probe(device_t dev)
287 {
288 
289 	device_set_desc(dev, "Econa CPU Timer");
290 	return (0);
291 }
292 
293 static int
ec_reset(void * arg)294 ec_reset(void *arg)
295 {
296 
297 	arm_mask_irq(1);
298 	clear_timer_interrupt_status(1);
299 	arm_unmask_irq(1);
300 	return (FILTER_HANDLED);
301 }
302 
303 static int
ec_hardclock(void * arg)304 ec_hardclock(void *arg)
305 {
306 	struct	trapframe *frame;
307 	unsigned int val;
308 	/*clear timer interrupt status*/
309 
310 	arm_mask_irq(0);
311 
312 	val = read_4(TIMER_INTERRUPT_STATUS_REG);
313 	val &= ~(TIMER1_OVERFLOW_INTERRUPT);
314 	write_4(val, TIMER_INTERRUPT_STATUS_REG);
315 
316 	frame = (struct trapframe *)arg;
317 	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
318 
319 	arm_unmask_irq(0);
320 
321 	return (FILTER_HANDLED);
322 }
323 
324 static int
ec_timer_attach(device_t dev)325 ec_timer_attach(device_t dev)
326 {
327 	struct	ec_timer_softc *sc;
328 	int	error;
329 	void	*ihl;
330 
331 
332 	if (timer_softc != NULL)
333 		return (ENXIO);
334 
335 	sc = (struct ec_timer_softc *)device_get_softc(dev);
336 
337 	timer_softc = sc;
338 
339 	error = bus_alloc_resources(dev, ec_timer_spec, sc->timer_res);
340 	if (error) {
341 		device_printf(dev, "could not allocate resources\n");
342 		return (ENXIO);
343 	}
344 
345 	sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
346 	sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
347 
348 	do_setup_timer();
349 
350 	if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
351 	    ec_hardclock, NULL, NULL, &ihl) != 0) {
352 		bus_release_resources(dev, ec_timer_spec, sc->timer_res);
353 		device_printf(dev, "could not setup hardclock interrupt\n");
354 		return (ENXIO);
355 	}
356 
357 	if (bus_setup_intr(dev, sc->timer_res[2], INTR_TYPE_CLK,
358 	    ec_reset, NULL, NULL, &ihl) != 0) {
359 		bus_release_resources(dev, ec_timer_spec, sc->timer_res);
360 		device_printf(dev, "could not setup timer interrupt\n");
361 		return (ENXIO);
362 	}
363 
364 	return (0);
365 }
366 
367 static device_method_t ec_timer_methods[] = {
368 	DEVMETHOD(device_probe, ec_timer_probe),
369 	DEVMETHOD(device_attach, ec_timer_attach),
370 	{ 0, 0 }
371 };
372 
373 static driver_t ec_timer_driver = {
374 	"timer",
375 	ec_timer_methods,
376 	sizeof(struct ec_timer_softc),
377 };
378 
379 static devclass_t ec_timer_devclass;
380 
381 DRIVER_MODULE(timer, econaarm, ec_timer_driver, ec_timer_devclass, 0, 0);
382