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