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