timer.c revision 295041
1295041Sbr/*-
2295041Sbr * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
3295041Sbr * All rights reserved.
4295041Sbr *
5295041Sbr * Portions of this software were developed by SRI International and the
6295041Sbr * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7295041Sbr * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8295041Sbr *
9295041Sbr * Portions of this software were developed by the University of Cambridge
10295041Sbr * Computer Laboratory as part of the CTSRD Project, with support from the
11295041Sbr * UK Higher Education Innovation Fund (HEIF).
12295041Sbr *
13295041Sbr * Redistribution and use in source and binary forms, with or without
14295041Sbr * modification, are permitted provided that the following conditions
15295041Sbr * are met:
16295041Sbr * 1. Redistributions of source code must retain the above copyright
17295041Sbr *    notice, this list of conditions and the following disclaimer.
18295041Sbr * 2. Redistributions in binary form must reproduce the above copyright
19295041Sbr *    notice, this list of conditions and the following disclaimer in the
20295041Sbr *    documentation and/or other materials provided with the distribution.
21295041Sbr *
22295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25295041Sbr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32295041Sbr * SUCH DAMAGE.
33295041Sbr */
34295041Sbr
35295041Sbr/*
36295041Sbr * RISC-V Timer
37295041Sbr */
38295041Sbr
39295041Sbr#include "opt_platform.h"
40295041Sbr
41295041Sbr#include <sys/cdefs.h>
42295041Sbr__FBSDID("$FreeBSD: head/sys/riscv/riscv/timer.c 295041 2016-01-29 15:12:31Z br $");
43295041Sbr
44295041Sbr#include <sys/param.h>
45295041Sbr#include <sys/systm.h>
46295041Sbr#include <sys/bus.h>
47295041Sbr#include <sys/kernel.h>
48295041Sbr#include <sys/module.h>
49295041Sbr#include <sys/malloc.h>
50295041Sbr#include <sys/rman.h>
51295041Sbr#include <sys/timeet.h>
52295041Sbr#include <sys/timetc.h>
53295041Sbr#include <sys/watchdog.h>
54295041Sbr
55295041Sbr#include <sys/proc.h>
56295041Sbr
57295041Sbr#include <machine/bus.h>
58295041Sbr#include <machine/cpu.h>
59295041Sbr#include <machine/intr.h>
60295041Sbr#include <machine/asm.h>
61295041Sbr#include <machine/trap.h>
62295041Sbr
63295041Sbr#include <dev/fdt/fdt_common.h>
64295041Sbr#include <dev/ofw/openfirm.h>
65295041Sbr#include <dev/ofw/ofw_bus.h>
66295041Sbr#include <dev/ofw/ofw_bus_subr.h>
67295041Sbr
68295041Sbr#define	DEFAULT_FREQ	1000000
69295041Sbr
70295041Sbrstruct riscv_tmr_softc {
71295041Sbr	struct resource		*res[1];
72295041Sbr	void			*ihl[1];
73295041Sbr	uint32_t		clkfreq;
74295041Sbr	struct eventtimer	et;
75295041Sbr};
76295041Sbr
77295041Sbrstatic struct riscv_tmr_softc *riscv_tmr_sc = NULL;
78295041Sbr
79295041Sbrstatic struct resource_spec timer_spec[] = {
80295041Sbr	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
81295041Sbr	{ -1, 0 }
82295041Sbr};
83295041Sbr
84295041Sbrstatic timecounter_get_t riscv_tmr_get_timecount;
85295041Sbr
86295041Sbrstatic struct timecounter riscv_tmr_timecount = {
87295041Sbr	.tc_name           = "RISC-V Timecounter",
88295041Sbr	.tc_get_timecount  = riscv_tmr_get_timecount,
89295041Sbr	.tc_poll_pps       = NULL,
90295041Sbr	.tc_counter_mask   = ~0u,
91295041Sbr	.tc_frequency      = 0,
92295041Sbr	.tc_quality        = 1000,
93295041Sbr};
94295041Sbr
95295041Sbrstatic long
96295041Sbrget_counts(void)
97295041Sbr{
98295041Sbr
99295041Sbr	return (csr_read(stime));
100295041Sbr}
101295041Sbr
102295041Sbrstatic unsigned
103295041Sbrriscv_tmr_get_timecount(struct timecounter *tc)
104295041Sbr{
105295041Sbr
106295041Sbr	return (get_counts());
107295041Sbr}
108295041Sbr
109295041Sbrstatic int
110295041Sbrriscv_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
111295041Sbr{
112295041Sbr	struct riscv_tmr_softc *sc;
113295041Sbr	int counts;
114295041Sbr
115295041Sbr	sc = (struct riscv_tmr_softc *)et->et_priv;
116295041Sbr
117295041Sbr	if (first != 0) {
118295041Sbr		counts = ((uint32_t)et->et_frequency * first) >> 32;
119295041Sbr		machine_command(ECALL_MTIMECMP, counts);
120295041Sbr		return (0);
121295041Sbr	}
122295041Sbr
123295041Sbr	return (EINVAL);
124295041Sbr
125295041Sbr}
126295041Sbr
127295041Sbrstatic int
128295041Sbrriscv_tmr_stop(struct eventtimer *et)
129295041Sbr{
130295041Sbr	struct riscv_tmr_softc *sc;
131295041Sbr
132295041Sbr	sc = (struct riscv_tmr_softc *)et->et_priv;
133295041Sbr
134295041Sbr	/* TODO */
135295041Sbr
136295041Sbr	return (0);
137295041Sbr}
138295041Sbr
139295041Sbrstatic int
140295041Sbrriscv_tmr_intr(void *arg)
141295041Sbr{
142295041Sbr	struct riscv_tmr_softc *sc;
143295041Sbr
144295041Sbr	sc = (struct riscv_tmr_softc *)arg;
145295041Sbr
146295041Sbr	/*
147295041Sbr	 * Clear interrupt pending bit.
148295041Sbr	 * Note sip register is unimplemented in Spike simulator,
149295041Sbr	 * so use machine command to clear in mip.
150295041Sbr	 */
151295041Sbr	machine_command(ECALL_CLEAR_PENDING, 0);
152295041Sbr
153295041Sbr	if (sc->et.et_active)
154295041Sbr		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
155295041Sbr
156295041Sbr	return (FILTER_HANDLED);
157295041Sbr}
158295041Sbr
159295041Sbrstatic int
160295041Sbrriscv_tmr_fdt_probe(device_t dev)
161295041Sbr{
162295041Sbr
163295041Sbr	if (!ofw_bus_status_okay(dev))
164295041Sbr		return (ENXIO);
165295041Sbr
166295041Sbr	if (ofw_bus_is_compatible(dev, "riscv,timer")) {
167295041Sbr		device_set_desc(dev, "RISC-V Timer");
168295041Sbr		return (BUS_PROBE_DEFAULT);
169295041Sbr	}
170295041Sbr
171295041Sbr	return (ENXIO);
172295041Sbr}
173295041Sbr
174295041Sbrstatic int
175295041Sbrriscv_tmr_attach(device_t dev)
176295041Sbr{
177295041Sbr	struct riscv_tmr_softc *sc;
178295041Sbr	phandle_t node;
179295041Sbr	pcell_t clock;
180295041Sbr	int error;
181295041Sbr
182295041Sbr	sc = device_get_softc(dev);
183295041Sbr	if (riscv_tmr_sc)
184295041Sbr		return (ENXIO);
185295041Sbr
186295041Sbr	/* Get the base clock frequency */
187295041Sbr	node = ofw_bus_get_node(dev);
188295041Sbr	if (node > 0) {
189295041Sbr		error = OF_getprop(node, "clock-frequency", &clock,
190295041Sbr		    sizeof(clock));
191295041Sbr		if (error > 0) {
192295041Sbr			sc->clkfreq = fdt32_to_cpu(clock);
193295041Sbr		}
194295041Sbr	}
195295041Sbr
196295041Sbr	if (sc->clkfreq == 0)
197295041Sbr		sc->clkfreq = DEFAULT_FREQ;
198295041Sbr
199295041Sbr	if (sc->clkfreq == 0) {
200295041Sbr		device_printf(dev, "No clock frequency specified\n");
201295041Sbr		return (ENXIO);
202295041Sbr	}
203295041Sbr
204295041Sbr	if (bus_alloc_resources(dev, timer_spec, sc->res)) {
205295041Sbr		device_printf(dev, "could not allocate resources\n");
206295041Sbr		return (ENXIO);
207295041Sbr	}
208295041Sbr
209295041Sbr	riscv_tmr_sc = sc;
210295041Sbr
211295041Sbr	/* Setup IRQs handler */
212295041Sbr	error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_CLK,
213295041Sbr	    riscv_tmr_intr, NULL, sc, &sc->ihl[0]);
214295041Sbr	if (error) {
215295041Sbr		device_printf(dev, "Unable to alloc int resource.\n");
216295041Sbr		return (ENXIO);
217295041Sbr	}
218295041Sbr
219295041Sbr	riscv_tmr_timecount.tc_frequency = sc->clkfreq;
220295041Sbr	tc_init(&riscv_tmr_timecount);
221295041Sbr
222295041Sbr	sc->et.et_name = "RISC-V Eventtimer";
223295041Sbr	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
224295041Sbr	sc->et.et_quality = 1000;
225295041Sbr
226295041Sbr	sc->et.et_frequency = sc->clkfreq;
227295041Sbr	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
228295041Sbr	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
229295041Sbr	sc->et.et_start = riscv_tmr_start;
230295041Sbr	sc->et.et_stop = riscv_tmr_stop;
231295041Sbr	sc->et.et_priv = sc;
232295041Sbr	et_register(&sc->et);
233295041Sbr
234295041Sbr	return (0);
235295041Sbr}
236295041Sbr
237295041Sbrstatic device_method_t riscv_tmr_fdt_methods[] = {
238295041Sbr	DEVMETHOD(device_probe,		riscv_tmr_fdt_probe),
239295041Sbr	DEVMETHOD(device_attach,	riscv_tmr_attach),
240295041Sbr	{ 0, 0 }
241295041Sbr};
242295041Sbr
243295041Sbrstatic driver_t riscv_tmr_fdt_driver = {
244295041Sbr	"timer",
245295041Sbr	riscv_tmr_fdt_methods,
246295041Sbr	sizeof(struct riscv_tmr_softc),
247295041Sbr};
248295041Sbr
249295041Sbrstatic devclass_t riscv_tmr_fdt_devclass;
250295041Sbr
251295041SbrEARLY_DRIVER_MODULE(timer, simplebus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass,
252295041Sbr    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
253295041SbrEARLY_DRIVER_MODULE(timer, ofwbus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass,
254295041Sbr    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
255295041Sbr
256295041Sbrvoid
257295041SbrDELAY(int usec)
258295041Sbr{
259295041Sbr	int32_t counts, counts_per_usec;
260295041Sbr	uint32_t first, last;
261295041Sbr
262295041Sbr	/*
263295041Sbr	 * Check the timers are setup, if not just
264295041Sbr	 * use a for loop for the meantime
265295041Sbr	 */
266295041Sbr	if (riscv_tmr_sc == NULL) {
267295041Sbr		for (; usec > 0; usec--)
268295041Sbr			for (counts = 200; counts > 0; counts--)
269295041Sbr				/*
270295041Sbr				 * Prevent the compiler from optimizing
271295041Sbr				 * out the loop
272295041Sbr				 */
273295041Sbr				cpufunc_nullop();
274295041Sbr		return;
275295041Sbr	}
276295041Sbr
277295041Sbr	/* Get the number of times to count */
278295041Sbr	counts_per_usec = ((riscv_tmr_timecount.tc_frequency / 1000000) + 1);
279295041Sbr
280295041Sbr	/*
281295041Sbr	 * Clamp the timeout at a maximum value (about 32 seconds with
282295041Sbr	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
283295041Sbr	 * near that length of time and if they are, they should be hung
284295041Sbr	 * out to dry.
285295041Sbr	 */
286295041Sbr	if (usec >= (0x80000000U / counts_per_usec))
287295041Sbr		counts = (0x80000000U / counts_per_usec) - 1;
288295041Sbr	else
289295041Sbr		counts = usec * counts_per_usec;
290295041Sbr
291295041Sbr	first = get_counts();
292295041Sbr
293295041Sbr	while (counts > 0) {
294295041Sbr		last = get_counts();
295295041Sbr		counts -= (int32_t)(last - first);
296295041Sbr		first = last;
297295041Sbr	}
298295041Sbr}
299