1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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
95struct 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
115static unsigned sp804_timer_tc_get_timecount(struct timecounter *);
116static void sp804_timer_delay(int, void *);
117
118static unsigned
119sp804_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
125static int
126sp804_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
152static int
153sp804_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
166static int
167sp804_timer_intr(void *arg)
168{
169	struct sp804_timer_softc *sc = arg;
170	static uint32_t prev = 0;
171	uint32_t x = 0;
172
173	x = sp804_timer_tc_read_4(SP804_TIMER1_VALUE);
174
175	prev =x ;
176	sp804_timer_tc_write_4(SP804_TIMER2_INTCLR, 1);
177	if (sc->et_enabled) {
178		if (sc->et.et_active) {
179			sc->et.et_event_cb(&sc->et, sc->et.et_arg);
180		}
181	}
182
183	return (FILTER_HANDLED);
184}
185
186static int
187sp804_timer_probe(device_t dev)
188{
189
190	if (!ofw_bus_status_okay(dev))
191		return (ENXIO);
192
193	if (ofw_bus_is_compatible(dev, "arm,sp804")) {
194		device_set_desc(dev, "SP804 System Timer");
195		return (BUS_PROBE_DEFAULT);
196	}
197
198	return (ENXIO);
199}
200
201static int
202sp804_timer_attach(device_t dev)
203{
204	struct sp804_timer_softc *sc = device_get_softc(dev);
205	int rid = 0;
206	int i;
207	uint32_t id, reg;
208	phandle_t node;
209	pcell_t clock;
210
211	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
212	if (sc->mem_res == NULL) {
213		device_printf(dev, "could not allocate memory resource\n");
214		return (ENXIO);
215	}
216
217	sc->bst = rman_get_bustag(sc->mem_res);
218	sc->bsh = rman_get_bushandle(sc->mem_res);
219
220	/* Request the IRQ resources */
221	sc->irq_res =  bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
222	if (sc->irq_res == NULL) {
223		device_printf(dev, "Error: could not allocate irq resources\n");
224		return (ENXIO);
225	}
226
227	sc->sysclk_freq = DEFAULT_FREQUENCY;
228	/* Get the base clock frequency */
229	node = ofw_bus_get_node(dev);
230	if ((OF_getencprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) {
231		sc->sysclk_freq = clock;
232	}
233
234	/* Setup and enable the timer */
235	if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK,
236			sp804_timer_intr, NULL, sc,
237			&sc->intr_hl) != 0) {
238		bus_release_resource(dev, SYS_RES_IRQ, rid,
239			sc->irq_res);
240		device_printf(dev, "Unable to setup the clock irq handler.\n");
241		return (ENXIO);
242	}
243
244	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, 0);
245	sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, 0);
246
247	/*
248	 * Timer 1, timecounter
249	 */
250	sc->tc.tc_frequency = sc->sysclk_freq;
251	sc->tc.tc_name = "SP804-1";
252	sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount;
253	sc->tc.tc_poll_pps = NULL;
254	sc->tc.tc_counter_mask = ~0u;
255	sc->tc.tc_quality = 1000;
256	sc->tc.tc_priv = sc;
257
258	sp804_timer_tc_write_4(SP804_TIMER1_VALUE, 0xffffffff);
259	sp804_timer_tc_write_4(SP804_TIMER1_LOAD, 0xffffffff);
260	reg = TIMER_CONTROL_PERIODIC | TIMER_CONTROL_32BIT;
261	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg);
262	reg |= TIMER_CONTROL_EN;
263	sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg);
264	tc_init(&sc->tc);
265
266	/*
267	 * Timer 2, event timer
268	 */
269	sc->et_enabled = 0;
270	sc->et.et_name = "SP804-2";
271	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
272	sc->et.et_quality = 1000;
273	sc->et.et_frequency = sc->sysclk_freq / DEFAULT_DIVISOR;
274	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
275	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
276	sc->et.et_start = sp804_timer_start;
277	sc->et.et_stop = sp804_timer_stop;
278	sc->et.et_priv = sc;
279	et_register(&sc->et);
280
281	id = 0;
282	for (i = 3; i >= 0; i--) {
283		id = (id << 8) |
284		     (sp804_timer_tc_read_4(SP804_PERIPH_ID0 + i*4) & 0xff);
285	}
286
287	device_printf(dev, "peripheral ID: %08x\n", id);
288
289	id = 0;
290	for (i = 3; i >= 0; i--) {
291		id = (id << 8) |
292		     (sp804_timer_tc_read_4(SP804_PRIMECELL_ID0 + i*4) & 0xff);
293	}
294
295	arm_set_delay(sp804_timer_delay, sc);
296
297	device_printf(dev, "PrimeCell ID: %08x\n", id);
298
299	sc->timer_initialized = 1;
300
301	return (0);
302}
303
304static device_method_t sp804_timer_methods[] = {
305	DEVMETHOD(device_probe,		sp804_timer_probe),
306	DEVMETHOD(device_attach,	sp804_timer_attach),
307	{ 0, 0 }
308};
309
310static driver_t sp804_timer_driver = {
311	"timer",
312	sp804_timer_methods,
313	sizeof(struct sp804_timer_softc),
314};
315
316static devclass_t sp804_timer_devclass;
317
318DRIVER_MODULE(sp804_timer, simplebus, sp804_timer_driver, sp804_timer_devclass, 0, 0);
319
320static void
321sp804_timer_delay(int usec, void *arg)
322{
323	struct sp804_timer_softc *sc = arg;
324	int32_t counts;
325	uint32_t first, last;
326
327	/* Get the number of times to count */
328	counts = usec * ((sc->tc.tc_frequency / 1000000) + 1);
329
330	first = sp804_timer_tc_get_timecount(&sc->tc);
331
332	while (counts > 0) {
333		last = sp804_timer_tc_get_timecount(&sc->tc);
334		if (last == first)
335			continue;
336		if (last > first) {
337			counts -= (int32_t)(last - first);
338		} else {
339			counts -= (int32_t)((0xFFFFFFFF - first) + last);
340		}
341		first = last;
342	}
343}
344