timer.c revision 245453
1/*-
2 * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@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 THE 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 THE 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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/arm/allwinner/timer.c 245453 2013-01-15 09:31:13Z ganbold $");
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/bus.h>
33#include <sys/kernel.h>
34#include <sys/module.h>
35#include <sys/malloc.h>
36#include <sys/rman.h>
37#include <sys/timeet.h>
38#include <sys/timetc.h>
39#include <sys/watchdog.h>
40#include <machine/bus.h>
41#include <machine/cpu.h>
42#include <machine/frame.h>
43#include <machine/intr.h>
44
45#include <dev/fdt/fdt_common.h>
46#include <dev/ofw/openfirm.h>
47#include <dev/ofw/ofw_bus.h>
48#include <dev/ofw/ofw_bus_subr.h>
49
50#include <machine/bus.h>
51#include <machine/fdt.h>
52
53#include <sys/kdb.h>
54
55/**
56 * Timer registers addr
57 *
58 */
59#define SW_TIMER_IRQ_EN_REG 	0x00
60#define SW_TIMER_IRQ_STA_REG 	0x04
61#define SW_TIMER0_CTRL_REG 	0x10
62#define SW_TIMER0_INT_VALUE_REG	0x14
63#define SW_TIMER0_CUR_VALUE_REG	0x18
64
65#define SYS_TIMER_SCAL		16 /* timer clock source pre-divsion */
66#define SYS_TIMER_CLKSRC	24000000 /* timer clock source */
67#define TMR_INTER_VAL		SYS_TIMER_CLKSRC/(SYS_TIMER_SCAL * 1000)
68
69#define CLOCK_TICK_RATE		TMR_INTER_VAL
70#define INITIAL_TIMECOUNTER	(0xffffffff)
71
72struct a10_timer_softc {
73	device_t 	sc_dev;
74	struct resource *res[2];
75	bus_space_tag_t sc_bst;
76	bus_space_handle_t sc_bsh;
77	void 		*sc_ih;		/* interrupt handler */
78	uint32_t 	sc_period;
79	uint32_t 	clkfreq;
80	struct eventtimer et;
81};
82
83int a10_timer_get_timerfreq(struct a10_timer_softc *);
84
85#define timer_read_4(sc, reg)	\
86	bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg)
87#define timer_write_4(sc, reg, val)	\
88	bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val)
89
90static u_int	a10_timer_get_timecount(struct timecounter *);
91static int	a10_timer_timer_start(struct eventtimer *,
92    struct bintime *, struct bintime *);
93static int	a10_timer_timer_stop(struct eventtimer *);
94
95static int a10_timer_initialized = 0;
96static int a10_timer_intr(void *);
97static int a10_timer_probe(device_t);
98static int a10_timer_attach(device_t);
99
100static struct timecounter a10_timer_timecounter = {
101	.tc_name           = "a10_timer timer0",
102	.tc_get_timecount  = a10_timer_get_timecount,
103	.tc_counter_mask   = ~0u,
104	.tc_frequency      = 0,
105	.tc_quality        = 1000,
106};
107
108struct a10_timer_softc *a10_timer_sc = NULL;
109
110static struct resource_spec a10_timer_spec[] = {
111	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
112	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
113	{ -1, 0 }
114};
115
116static int
117a10_timer_probe(device_t dev)
118{
119
120	if (!ofw_bus_is_compatible(dev, "a10,timers"))
121		return (ENXIO);
122
123	device_set_desc(dev, "Allwinner A10 timer");
124	return (BUS_PROBE_DEFAULT);
125}
126
127static int
128a10_timer_attach(device_t dev)
129{
130	struct a10_timer_softc *sc;
131	int err;
132	uint32_t val;
133	uint32_t freq;
134
135	sc = device_get_softc(dev);
136
137	if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) {
138		device_printf(dev, "could not allocate resources\n");
139		return (ENXIO);
140	}
141
142	sc->sc_dev = dev;
143	sc->sc_bst = rman_get_bustag(sc->res[0]);
144	sc->sc_bsh = rman_get_bushandle(sc->res[0]);
145
146	/* set interval */
147	timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, TMR_INTER_VAL);
148
149	/* set clock source to HOSC, 16 pre-division */
150	val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
151	val &= ~(0x07<<4);
152	val &= ~(0x03<<2);
153	val |= (4<<4) | (1<<2);
154	timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
155
156	/* set mode to auto reload */
157	val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
158	val |= (1<<1);
159	timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
160
161	/* Enable timer0 */
162	val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG);
163	val |= (1<<0);
164	timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val);
165
166	/* Setup and enable the timer interrupt */
167	err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_intr,
168	    NULL, sc, &sc->sc_ih);
169	if (err != 0) {
170		bus_release_resources(dev, a10_timer_spec, sc->res);
171		device_printf(dev, "Unable to setup the clock irq handler, "
172		    "err = %d\n", err);
173		return (ENXIO);
174	}
175	freq = SYS_TIMER_CLKSRC;
176
177        /* Set desired frequency in event timer and timecounter */
178	sc->et.et_frequency = (uint64_t)freq;
179	sc->clkfreq = (uint64_t)freq;
180	sc->et.et_name = "a10_timer Eventtimer";
181	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
182	sc->et.et_quality = 1000;
183	sc->et.et_min_period.sec = 0;
184	sc->et.et_min_period.frac =
185	    ((0x00000002LLU << 32) / sc->et.et_frequency) << 32;
186	sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency;
187	sc->et.et_max_period.frac =
188	    ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
189	sc->et.et_start = a10_timer_timer_start;
190	sc->et.et_stop = a10_timer_timer_stop;
191	sc->et.et_priv = sc;
192	et_register(&sc->et);
193
194	if (device_get_unit(dev) == 0)
195		a10_timer_sc = sc;
196
197	a10_timer_timecounter.tc_frequency = (uint64_t)freq;
198	tc_init(&a10_timer_timecounter);
199
200	printf("clock: hz=%d stathz = %d\n", hz, stathz);
201
202	device_printf(sc->sc_dev, "timer clock frequency %d\n", sc->clkfreq);
203
204	a10_timer_initialized = 1;
205
206	return (0);
207}
208
209static int
210a10_timer_timer_start(struct eventtimer *et, struct bintime *first,
211    struct bintime *period)
212{
213	struct a10_timer_softc *sc;
214	uint32_t clo, count;
215
216	sc = (struct a10_timer_softc *)et->et_priv;
217
218	if (first != NULL) {
219		count = (sc->et.et_frequency * (first->frac >> 32)) >> 32;
220		if (first->sec != 0)
221			count += sc->et.et_frequency * first->sec;
222
223		/* clear */
224		timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, 0);
225		clo = timer_read_4(sc, SW_TIMER0_CUR_VALUE_REG);
226		clo += count;
227		timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, clo);
228
229		return (0);
230	}
231
232	return (EINVAL);
233}
234
235static int
236a10_timer_timer_stop(struct eventtimer *et)
237{
238	struct a10_timer_softc *sc;
239	uint32_t val;
240
241	sc = (struct a10_timer_softc *)et->et_priv;
242
243	/* clear */
244	timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, 0);
245
246	/* disable */
247	val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
248	val &= ~(1<<0); /* Disable timer0 */
249	timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
250
251	sc->sc_period = 0;
252
253	return (0);
254}
255
256int
257a10_timer_get_timerfreq(struct a10_timer_softc *sc)
258{
259
260	return (sc->clkfreq);
261}
262
263void
264cpu_initclocks(void)
265{
266	cpu_initclocks_bsp();
267}
268
269static int
270a10_timer_intr(void *arg)
271{
272	struct a10_timer_softc *sc;
273
274	sc = (struct a10_timer_softc *)arg;
275
276	if (sc->et.et_active)
277		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
278
279	/* pending */
280	timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1);
281
282	return (FILTER_HANDLED);
283}
284
285u_int
286a10_timer_get_timecount(struct timecounter *tc)
287{
288
289	if (a10_timer_sc == NULL)
290		return (0);
291
292	return (timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG));
293}
294
295static device_method_t a10_timer_methods[] = {
296	DEVMETHOD(device_probe,		a10_timer_probe),
297	DEVMETHOD(device_attach,	a10_timer_attach),
298
299	DEVMETHOD_END
300};
301
302static driver_t a10_timer_driver = {
303	"a10_timer",
304	a10_timer_methods,
305	sizeof(struct a10_timer_softc),
306};
307
308static devclass_t a10_timer_devclass;
309
310DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0);
311
312void
313DELAY(int usec)
314{
315	uint32_t counter;
316	uint32_t val, val_temp;
317	int32_t nticks;
318
319	/* Timer is not initialized yet */
320	if (!a10_timer_initialized) {
321		for (; usec > 0; usec--)
322			for (counter = 200; counter > 0; counter--)
323				/* Prevent optimizing out the loop */
324				cpufunc_nullop();
325		return;
326	}
327
328	val = timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG);
329        nticks = ((a10_timer_sc->clkfreq / 1000000 + 1) * usec);
330
331        while (nticks > 0) {
332                val_temp = timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG);
333                if (val > val_temp)
334                        nticks -= (val - val_temp);
335                else
336                        nticks -= (val + (INITIAL_TIMECOUNTER - val_temp));
337
338                val = val_temp;
339        }
340}
341
342