1 /*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * RISC-V Timer 37 */ 38 39 #include "opt_platform.h" 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/bus.h> 47 #include <sys/kernel.h> 48 #include <sys/module.h> 49 #include <sys/malloc.h> 50 #include <sys/rman.h> 51 #include <sys/timeet.h> 52 #include <sys/timetc.h> 53 #include <sys/watchdog.h> 54 55 #include <sys/proc.h> 56 57 #include <machine/bus.h> 58 #include <machine/cpu.h> 59 #include <machine/intr.h> 60 #include <machine/asm.h> 61 #include <machine/trap.h> 62 63 #include <dev/fdt/fdt_common.h> 64 #include <dev/ofw/openfirm.h> 65 #include <dev/ofw/ofw_bus.h> 66 #include <dev/ofw/ofw_bus_subr.h> 67 68 #define DEFAULT_FREQ 1000000 69 70 struct riscv_tmr_softc { 71 struct resource *res[1]; 72 void *ihl[1]; 73 uint32_t clkfreq; 74 struct eventtimer et; 75 }; 76 77 static struct riscv_tmr_softc *riscv_tmr_sc = NULL; 78 79 static struct resource_spec timer_spec[] = { 80 { SYS_RES_IRQ, 0, RF_ACTIVE }, 81 { -1, 0 } 82 }; 83 84 static timecounter_get_t riscv_tmr_get_timecount; 85 86 static struct timecounter riscv_tmr_timecount = { 87 .tc_name = "RISC-V Timecounter", 88 .tc_get_timecount = riscv_tmr_get_timecount, 89 .tc_poll_pps = NULL, 90 .tc_counter_mask = ~0u, 91 .tc_frequency = 0, 92 .tc_quality = 1000, 93 }; 94 95 static long 96 get_counts(void) 97 { 98 99 return (csr_read(stime)); 100 } 101 102 static unsigned 103 riscv_tmr_get_timecount(struct timecounter *tc) 104 { 105 106 return (get_counts()); 107 } 108 109 static int 110 riscv_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 111 { 112 struct riscv_tmr_softc *sc; 113 int counts; 114 115 sc = (struct riscv_tmr_softc *)et->et_priv; 116 117 if (first != 0) { 118 counts = ((uint32_t)et->et_frequency * first) >> 32; 119 machine_command(ECALL_MTIMECMP, counts); 120 return (0); 121 } 122 123 return (EINVAL); 124 125 } 126 127 static int 128 riscv_tmr_stop(struct eventtimer *et) 129 { 130 struct riscv_tmr_softc *sc; 131 132 sc = (struct riscv_tmr_softc *)et->et_priv; 133 134 /* TODO */ 135 136 return (0); 137 } 138 139 static int 140 riscv_tmr_intr(void *arg) 141 { 142 struct riscv_tmr_softc *sc; 143 144 sc = (struct riscv_tmr_softc *)arg; 145 146 /* 147 * Clear interrupt pending bit. 148 * Note sip register is unimplemented in Spike simulator, 149 * so use machine command to clear in mip. 150 */ 151 machine_command(ECALL_CLEAR_PENDING, 0); 152 153 if (sc->et.et_active) 154 sc->et.et_event_cb(&sc->et, sc->et.et_arg); 155 156 return (FILTER_HANDLED); 157 } 158 159 static int 160 riscv_tmr_fdt_probe(device_t dev) 161 { 162 163 if (!ofw_bus_status_okay(dev)) 164 return (ENXIO); 165 166 if (ofw_bus_is_compatible(dev, "riscv,timer")) { 167 device_set_desc(dev, "RISC-V Timer"); 168 return (BUS_PROBE_DEFAULT); 169 } 170 171 return (ENXIO); 172 } 173 174 static int 175 riscv_tmr_attach(device_t dev) 176 { 177 struct riscv_tmr_softc *sc; 178 phandle_t node; 179 pcell_t clock; 180 int error; 181 182 sc = device_get_softc(dev); 183 if (riscv_tmr_sc) 184 return (ENXIO); 185 186 /* Get the base clock frequency */ 187 node = ofw_bus_get_node(dev); 188 if (node > 0) { 189 error = OF_getprop(node, "clock-frequency", &clock, 190 sizeof(clock)); 191 if (error > 0) { 192 sc->clkfreq = fdt32_to_cpu(clock); 193 } 194 } 195 196 if (sc->clkfreq == 0) 197 sc->clkfreq = DEFAULT_FREQ; 198 199 if (sc->clkfreq == 0) { 200 device_printf(dev, "No clock frequency specified\n"); 201 return (ENXIO); 202 } 203 204 if (bus_alloc_resources(dev, timer_spec, sc->res)) { 205 device_printf(dev, "could not allocate resources\n"); 206 return (ENXIO); 207 } 208 209 riscv_tmr_sc = sc; 210 211 /* Setup IRQs handler */ 212 error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_CLK, 213 riscv_tmr_intr, NULL, sc, &sc->ihl[0]); 214 if (error) { 215 device_printf(dev, "Unable to alloc int resource.\n"); 216 return (ENXIO); 217 } 218 219 riscv_tmr_timecount.tc_frequency = sc->clkfreq; 220 tc_init(&riscv_tmr_timecount); 221 222 sc->et.et_name = "RISC-V Eventtimer"; 223 sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 224 sc->et.et_quality = 1000; 225 226 sc->et.et_frequency = sc->clkfreq; 227 sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 228 sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 229 sc->et.et_start = riscv_tmr_start; 230 sc->et.et_stop = riscv_tmr_stop; 231 sc->et.et_priv = sc; 232 et_register(&sc->et); 233 234 return (0); 235 } 236 237 static device_method_t riscv_tmr_fdt_methods[] = { 238 DEVMETHOD(device_probe, riscv_tmr_fdt_probe), 239 DEVMETHOD(device_attach, riscv_tmr_attach), 240 { 0, 0 } 241 }; 242 243 static driver_t riscv_tmr_fdt_driver = { 244 "timer", 245 riscv_tmr_fdt_methods, 246 sizeof(struct riscv_tmr_softc), 247 }; 248 249 static devclass_t riscv_tmr_fdt_devclass; 250 251 EARLY_DRIVER_MODULE(timer, simplebus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass, 252 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 253 EARLY_DRIVER_MODULE(timer, ofwbus, riscv_tmr_fdt_driver, riscv_tmr_fdt_devclass, 254 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 255 256 void 257 DELAY(int usec) 258 { 259 int32_t counts, counts_per_usec; 260 uint32_t first, last; 261 262 /* 263 * Check the timers are setup, if not just 264 * use a for loop for the meantime 265 */ 266 if (riscv_tmr_sc == NULL) { 267 for (; usec > 0; usec--) 268 for (counts = 200; counts > 0; counts--) 269 /* 270 * Prevent the compiler from optimizing 271 * out the loop 272 */ 273 cpufunc_nullop(); 274 return; 275 } 276 277 /* Get the number of times to count */ 278 counts_per_usec = ((riscv_tmr_timecount.tc_frequency / 1000000) + 1); 279 280 /* 281 * Clamp the timeout at a maximum value (about 32 seconds with 282 * a 66MHz clock). *Nobody* should be delay()ing for anywhere 283 * near that length of time and if they are, they should be hung 284 * out to dry. 285 */ 286 if (usec >= (0x80000000U / counts_per_usec)) 287 counts = (0x80000000U / counts_per_usec) - 1; 288 else 289 counts = usec * counts_per_usec; 290 291 first = get_counts(); 292 293 while (counts > 0) { 294 last = get_counts(); 295 counts -= (int32_t)(last - first); 296 first = last; 297 } 298 } 299