xref: /freebsd/sys/arm/arm/sp804.c (revision bdd1243d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
5  * Copyright (c) 2012 Damjan Marion <dmarion@freebsd.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 
40 #include <sys/timeet.h>
41 #include <sys/timetc.h>
42 #include <sys/watchdog.h>
43 #include <machine/bus.h>
44 #include <machine/cpu.h>
45 #include <machine/intr.h>
46 
47 #include <machine/machdep.h> /* For arm_set_delay */
48 
49 #include <dev/ofw/openfirm.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 #include <machine/bus.h>
54 
55 #define	SP804_TIMER1_LOAD	0x00
56 #define	SP804_TIMER1_VALUE	0x04
57 #define	SP804_TIMER1_CONTROL	0x08
58 #define		TIMER_CONTROL_EN	(1 << 7)
59 #define		TIMER_CONTROL_FREERUN	(0 << 6)
60 #define		TIMER_CONTROL_PERIODIC	(1 << 6)
61 #define		TIMER_CONTROL_INTREN	(1 << 5)
62 #define		TIMER_CONTROL_DIV1	(0 << 2)
63 #define		TIMER_CONTROL_DIV16	(1 << 2)
64 #define		TIMER_CONTROL_DIV256	(2 << 2)
65 #define		TIMER_CONTROL_32BIT	(1 << 1)
66 #define		TIMER_CONTROL_ONESHOT	(1 << 0)
67 #define	SP804_TIMER1_INTCLR	0x0C
68 #define	SP804_TIMER1_RIS	0x10
69 #define	SP804_TIMER1_MIS	0x14
70 #define	SP804_TIMER1_BGLOAD	0x18
71 #define	SP804_TIMER2_LOAD	0x20
72 #define	SP804_TIMER2_VALUE	0x24
73 #define	SP804_TIMER2_CONTROL	0x28
74 #define	SP804_TIMER2_INTCLR	0x2C
75 #define	SP804_TIMER2_RIS	0x30
76 #define	SP804_TIMER2_MIS	0x34
77 #define	SP804_TIMER2_BGLOAD	0x38
78 
79 #define	SP804_PERIPH_ID0	0xFE0
80 #define	SP804_PERIPH_ID1	0xFE4
81 #define	SP804_PERIPH_ID2	0xFE8
82 #define	SP804_PERIPH_ID3	0xFEC
83 #define	SP804_PRIMECELL_ID0	0xFF0
84 #define	SP804_PRIMECELL_ID1	0xFF4
85 #define	SP804_PRIMECELL_ID2	0xFF8
86 #define	SP804_PRIMECELL_ID3	0xFFC
87 
88 #define	DEFAULT_FREQUENCY	1000000
89 /*
90  * QEMU seems to have problem with full frequency
91  */
92 #define	DEFAULT_DIVISOR		16
93 #define	DEFAULT_CONTROL_DIV	TIMER_CONTROL_DIV16
94 
95 struct sp804_timer_softc {
96 	struct resource*	mem_res;
97 	struct resource*	irq_res;
98 	void*			intr_hl;
99 	uint32_t		sysclk_freq;
100 	bus_space_tag_t		bst;
101 	bus_space_handle_t	bsh;
102 	struct timecounter	tc;
103 	bool			et_enabled;
104 	struct eventtimer	et;
105 	int			timer_initialized;
106 };
107 
108 /* Read/Write macros for Timer used as timecounter */
109 #define sp804_timer_tc_read_4(reg)		\
110 	bus_space_read_4(sc->bst, sc->bsh, reg)
111 
112 #define sp804_timer_tc_write_4(reg, val)	\
113 	bus_space_write_4(sc->bst, sc->bsh, reg, val)
114 
115 static unsigned sp804_timer_tc_get_timecount(struct timecounter *);
116 static void sp804_timer_delay(int, void *);
117 
118 static unsigned
119 sp804_timer_tc_get_timecount(struct timecounter *tc)
120 {
121 	struct sp804_timer_softc *sc = tc->tc_priv;
122 	return 0xffffffff - sp804_timer_tc_read_4(SP804_TIMER1_VALUE);
123 }
124 
125 static int
126 sp804_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
127 {
128 	struct sp804_timer_softc *sc = et->et_priv;
129 	uint32_t count, reg;
130 
131 	if (first != 0) {
132 		sc->et_enabled = 1;
133 
134 		count = ((uint32_t)et->et_frequency * first) >> 32;
135 
136 		sp804_timer_tc_write_4(SP804_TIMER2_LOAD, count);
137 		reg = TIMER_CONTROL_32BIT | TIMER_CONTROL_INTREN |
138 		    TIMER_CONTROL_PERIODIC | DEFAULT_CONTROL_DIV |
139 		    TIMER_CONTROL_EN;
140 		sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg);
141 
142 		return (0);
143 	}
144 
145 	if (period != 0) {
146 		panic("period");
147 	}
148 
149 	return (EINVAL);
150 }
151 
152 static int
153 sp804_timer_stop(struct eventtimer *et)
154 {
155 	struct sp804_timer_softc *sc = et->et_priv;
156 	uint32_t reg;
157 
158 	sc->et_enabled = 0;
159 	reg = sp804_timer_tc_read_4(SP804_TIMER2_CONTROL);
160 	reg &= ~(TIMER_CONTROL_EN);
161 	sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg);
162 
163 	return (0);
164 }
165 
166 static int
167 sp804_timer_intr(void *arg)
168 {
169 	struct sp804_timer_softc *sc = arg;
170 
171 	(void)sp804_timer_tc_read_4(SP804_TIMER1_VALUE);
172 
173 	sp804_timer_tc_write_4(SP804_TIMER2_INTCLR, 1);
174 	if (sc->et_enabled) {
175 		if (sc->et.et_active) {
176 			sc->et.et_event_cb(&sc->et, sc->et.et_arg);
177 		}
178 	}
179 
180 	return (FILTER_HANDLED);
181 }
182 
183 static int
184 sp804_timer_probe(device_t dev)
185 {
186 
187 	if (!ofw_bus_status_okay(dev))
188 		return (ENXIO);
189 
190 	if (ofw_bus_is_compatible(dev, "arm,sp804")) {
191 		device_set_desc(dev, "SP804 System Timer");
192 		return (BUS_PROBE_DEFAULT);
193 	}
194 
195 	return (ENXIO);
196 }
197 
198 static int
199 sp804_timer_attach(device_t dev)
200 {
201 	struct sp804_timer_softc *sc = device_get_softc(dev);
202 	int rid = 0;
203 	int i;
204 	uint32_t id, reg;
205 	phandle_t node;
206 	pcell_t clock;
207 
208 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
209 	if (sc->mem_res == NULL) {
210 		device_printf(dev, "could not allocate memory resource\n");
211 		return (ENXIO);
212 	}
213 
214 	sc->bst = rman_get_bustag(sc->mem_res);
215 	sc->bsh = rman_get_bushandle(sc->mem_res);
216 
217 	/* Request the IRQ resources */
218 	sc->irq_res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
219 	if (sc->irq_res == NULL) {
220 		device_printf(dev, "Error: could not allocate irq resources\n");
221 		return (ENXIO);
222 	}
223 
224 	sc->sysclk_freq = DEFAULT_FREQUENCY;
225 	/* Get the base clock frequency */
226 	node = ofw_bus_get_node(dev);
227 	if ((OF_getencprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) {
228 		sc->sysclk_freq = clock;
229 	}
230 
231 	/* Setup and enable the timer */
232 	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK,
233 			sp804_timer_intr, NULL, sc,
234 			&sc->intr_hl) != 0) {
235 		bus_release_resource(dev, SYS_RES_IRQ, rid,
236 			sc->irq_res);
237 		device_printf(dev, "Unable to setup the clock irq handler.\n");
238 		return (ENXIO);
239 	}
240 
241 	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, 0);
242 	sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, 0);
243 
244 	/*
245 	 * Timer 1, timecounter
246 	 */
247 	sc->tc.tc_frequency = sc->sysclk_freq;
248 	sc->tc.tc_name = "SP804-1";
249 	sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount;
250 	sc->tc.tc_poll_pps = NULL;
251 	sc->tc.tc_counter_mask = ~0u;
252 	sc->tc.tc_quality = 1000;
253 	sc->tc.tc_priv = sc;
254 
255 	sp804_timer_tc_write_4(SP804_TIMER1_VALUE, 0xffffffff);
256 	sp804_timer_tc_write_4(SP804_TIMER1_LOAD, 0xffffffff);
257 	reg = TIMER_CONTROL_PERIODIC | TIMER_CONTROL_32BIT;
258 	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg);
259 	reg |= TIMER_CONTROL_EN;
260 	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg);
261 	tc_init(&sc->tc);
262 
263 	/*
264 	 * Timer 2, event timer
265 	 */
266 	sc->et_enabled = 0;
267 	sc->et.et_name = "SP804-2";
268 	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
269 	sc->et.et_quality = 1000;
270 	sc->et.et_frequency = sc->sysclk_freq / DEFAULT_DIVISOR;
271 	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
272 	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
273 	sc->et.et_start = sp804_timer_start;
274 	sc->et.et_stop = sp804_timer_stop;
275 	sc->et.et_priv = sc;
276 	et_register(&sc->et);
277 
278 	id = 0;
279 	for (i = 3; i >= 0; i--) {
280 		id = (id << 8) |
281 		     (sp804_timer_tc_read_4(SP804_PERIPH_ID0 + i*4) & 0xff);
282 	}
283 
284 	device_printf(dev, "peripheral ID: %08x\n", id);
285 
286 	id = 0;
287 	for (i = 3; i >= 0; i--) {
288 		id = (id << 8) |
289 		     (sp804_timer_tc_read_4(SP804_PRIMECELL_ID0 + i*4) & 0xff);
290 	}
291 
292 	arm_set_delay(sp804_timer_delay, sc);
293 
294 	device_printf(dev, "PrimeCell ID: %08x\n", id);
295 
296 	sc->timer_initialized = 1;
297 
298 	return (0);
299 }
300 
301 static device_method_t sp804_timer_methods[] = {
302 	DEVMETHOD(device_probe,		sp804_timer_probe),
303 	DEVMETHOD(device_attach,	sp804_timer_attach),
304 	{ 0, 0 }
305 };
306 
307 static driver_t sp804_timer_driver = {
308 	"timer",
309 	sp804_timer_methods,
310 	sizeof(struct sp804_timer_softc),
311 };
312 
313 DRIVER_MODULE(sp804_timer, simplebus, sp804_timer_driver, 0, 0);
314 
315 static void
316 sp804_timer_delay(int usec, void *arg)
317 {
318 	struct sp804_timer_softc *sc = arg;
319 	int32_t counts;
320 	uint32_t first, last;
321 
322 	/* Get the number of times to count */
323 	counts = usec * ((sc->tc.tc_frequency / 1000000) + 1);
324 
325 	first = sp804_timer_tc_get_timecount(&sc->tc);
326 
327 	while (counts > 0) {
328 		last = sp804_timer_tc_get_timecount(&sc->tc);
329 		if (last == first)
330 			continue;
331 		if (last > first) {
332 			counts -= (int32_t)(last - first);
333 		} else {
334 			counts -= (int32_t)((0xFFFFFFFF - first) + last);
335 		}
336 		first = last;
337 	}
338 }
339