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$");
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.
148295892Sbr	 * Note: SIP_STIP bit is not implemented in sip register
149295892Sbr	 * in Spike simulator, so use machine command to clear
150295892Sbr	 * interrupt pending bit in mip.
151295041Sbr	 */
152295041Sbr	machine_command(ECALL_CLEAR_PENDING, 0);
153295041Sbr
154295041Sbr	if (sc->et.et_active)
155295041Sbr		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
156295041Sbr
157295041Sbr	return (FILTER_HANDLED);
158295041Sbr}
159295041Sbr
160295041Sbrstatic int
161295041Sbrriscv_tmr_fdt_probe(device_t dev)
162295041Sbr{
163295041Sbr
164295041Sbr	if (!ofw_bus_status_okay(dev))
165295041Sbr		return (ENXIO);
166295041Sbr
167295041Sbr	if (ofw_bus_is_compatible(dev, "riscv,timer")) {
168295041Sbr		device_set_desc(dev, "RISC-V Timer");
169295041Sbr		return (BUS_PROBE_DEFAULT);
170295041Sbr	}
171295041Sbr
172295041Sbr	return (ENXIO);
173295041Sbr}
174295041Sbr
175295041Sbrstatic int
176295041Sbrriscv_tmr_attach(device_t dev)
177295041Sbr{
178295041Sbr	struct riscv_tmr_softc *sc;
179295041Sbr	phandle_t node;
180295041Sbr	pcell_t clock;
181295041Sbr	int error;
182295041Sbr
183295041Sbr	sc = device_get_softc(dev);
184295041Sbr	if (riscv_tmr_sc)
185295041Sbr		return (ENXIO);
186295041Sbr
187295041Sbr	/* Get the base clock frequency */
188295041Sbr	node = ofw_bus_get_node(dev);
189295041Sbr	if (node > 0) {
190295041Sbr		error = OF_getprop(node, "clock-frequency", &clock,
191295041Sbr		    sizeof(clock));
192295041Sbr		if (error > 0) {
193295041Sbr			sc->clkfreq = fdt32_to_cpu(clock);
194295041Sbr		}
195295041Sbr	}
196295041Sbr
197295041Sbr	if (sc->clkfreq == 0)
198295041Sbr		sc->clkfreq = DEFAULT_FREQ;
199295041Sbr
200295041Sbr	if (sc->clkfreq == 0) {
201295041Sbr		device_printf(dev, "No clock frequency specified\n");
202295041Sbr		return (ENXIO);
203295041Sbr	}
204295041Sbr
205295041Sbr	if (bus_alloc_resources(dev, timer_spec, sc->res)) {
206295041Sbr		device_printf(dev, "could not allocate resources\n");
207295041Sbr		return (ENXIO);
208295041Sbr	}
209295041Sbr
210295041Sbr	riscv_tmr_sc = sc;
211295041Sbr
212295041Sbr	/* Setup IRQs handler */
213295041Sbr	error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_CLK,
214295041Sbr	    riscv_tmr_intr, NULL, sc, &sc->ihl[0]);
215295041Sbr	if (error) {
216295041Sbr		device_printf(dev, "Unable to alloc int resource.\n");
217295041Sbr		return (ENXIO);
218295041Sbr	}
219295041Sbr
220295041Sbr	riscv_tmr_timecount.tc_frequency = sc->clkfreq;
221295041Sbr	tc_init(&riscv_tmr_timecount);
222295041Sbr
223295041Sbr	sc->et.et_name = "RISC-V Eventtimer";
224295041Sbr	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
225295041Sbr	sc->et.et_quality = 1000;
226295041Sbr
227295041Sbr	sc->et.et_frequency = sc->clkfreq;
228295041Sbr	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
229295041Sbr	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
230295041Sbr	sc->et.et_start = riscv_tmr_start;
231295041Sbr	sc->et.et_stop = riscv_tmr_stop;
232295041Sbr	sc->et.et_priv = sc;
233295041Sbr	et_register(&sc->et);
234295041Sbr
235295041Sbr	return (0);
236295041Sbr}
237295041Sbr
238295041Sbrstatic device_method_t riscv_tmr_fdt_methods[] = {
239295041Sbr	DEVMETHOD(device_probe,		riscv_tmr_fdt_probe),
240295041Sbr	DEVMETHOD(device_attach,	riscv_tmr_attach),
241295041Sbr	{ 0, 0 }
242295041Sbr};
243295041Sbr
244295041Sbrstatic driver_t riscv_tmr_fdt_driver = {
245295041Sbr	"timer",
246295041Sbr	riscv_tmr_fdt_methods,
247295041Sbr	sizeof(struct riscv_tmr_softc),
248295041Sbr};
249295041Sbr
250295041Sbrstatic devclass_t riscv_tmr_fdt_devclass;
251295041Sbr
252295041SbrEARLY_DRIVER_MODULE(timer, simplebus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass,
253295041Sbr    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
254295041SbrEARLY_DRIVER_MODULE(timer, ofwbus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass,
255295041Sbr    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
256295041Sbr
257295041Sbrvoid
258295041SbrDELAY(int usec)
259295041Sbr{
260295041Sbr	int32_t counts, counts_per_usec;
261295041Sbr	uint32_t first, last;
262295041Sbr
263295041Sbr	/*
264295041Sbr	 * Check the timers are setup, if not just
265295041Sbr	 * use a for loop for the meantime
266295041Sbr	 */
267295041Sbr	if (riscv_tmr_sc == NULL) {
268295041Sbr		for (; usec > 0; usec--)
269295041Sbr			for (counts = 200; counts > 0; counts--)
270295041Sbr				/*
271295041Sbr				 * Prevent the compiler from optimizing
272295041Sbr				 * out the loop
273295041Sbr				 */
274295041Sbr				cpufunc_nullop();
275295041Sbr		return;
276295041Sbr	}
277295041Sbr
278295041Sbr	/* Get the number of times to count */
279295041Sbr	counts_per_usec = ((riscv_tmr_timecount.tc_frequency / 1000000) + 1);
280295041Sbr
281295041Sbr	/*
282295041Sbr	 * Clamp the timeout at a maximum value (about 32 seconds with
283295041Sbr	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
284295041Sbr	 * near that length of time and if they are, they should be hung
285295041Sbr	 * out to dry.
286295041Sbr	 */
287295041Sbr	if (usec >= (0x80000000U / counts_per_usec))
288295041Sbr		counts = (0x80000000U / counts_per_usec) - 1;
289295041Sbr	else
290295041Sbr		counts = usec * counts_per_usec;
291295041Sbr
292295041Sbr	first = get_counts();
293295041Sbr
294295041Sbr	while (counts > 0) {
295295041Sbr		last = get_counts();
296295041Sbr		counts -= (int32_t)(last - first);
297295041Sbr		first = last;
298295041Sbr	}
299295041Sbr}
300