1/* 2 * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 3 * Copyright (c) 2012 Damjan Marion <dmarion@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: stable/11/sys/arm/broadcom/bcm2835/bcm2835_systimer.c 331894 2018-04-02 23:30:21Z gonzo $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/bus.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/malloc.h> 37#include <sys/rman.h> 38#include <sys/timeet.h> 39#include <sys/timetc.h> 40#include <sys/watchdog.h> 41#include <machine/bus.h> 42#include <machine/cpu.h> 43#include <machine/intr.h> 44#include <machine/machdep.h> 45 46#include <dev/fdt/fdt_common.h> 47#include <dev/ofw/openfirm.h> 48#include <dev/ofw/ofw_bus.h> 49#include <dev/ofw/ofw_bus_subr.h> 50 51#include <machine/bus.h> 52 53#define BCM2835_NUM_TIMERS 4 54 55#define DEFAULT_TIMER 3 56#define DEFAULT_TIMER_NAME "BCM2835-3" 57#define DEFAULT_FREQUENCY 1000000 58#define MIN_PERIOD 5LLU 59 60#define SYSTIMER_CS 0x00 61#define SYSTIMER_CLO 0x04 62#define SYSTIMER_CHI 0x08 63#define SYSTIMER_C0 0x0C 64#define SYSTIMER_C1 0x10 65#define SYSTIMER_C2 0x14 66#define SYSTIMER_C3 0x18 67 68struct systimer { 69 int index; 70 bool enabled; 71 struct eventtimer et; 72}; 73 74struct bcm_systimer_softc { 75 struct resource* mem_res; 76 struct resource* irq_res[BCM2835_NUM_TIMERS]; 77 void* intr_hl[BCM2835_NUM_TIMERS]; 78 uint32_t sysclk_freq; 79 bus_space_tag_t bst; 80 bus_space_handle_t bsh; 81 struct systimer st[BCM2835_NUM_TIMERS]; 82}; 83 84static struct resource_spec bcm_systimer_irq_spec[] = { 85 { SYS_RES_IRQ, 0, RF_ACTIVE }, 86 { SYS_RES_IRQ, 1, RF_ACTIVE }, 87 { SYS_RES_IRQ, 2, RF_ACTIVE }, 88 { SYS_RES_IRQ, 3, RF_ACTIVE }, 89 { -1, 0, 0 } 90}; 91 92static struct bcm_systimer_softc *bcm_systimer_sc = NULL; 93 94/* Read/Write macros for Timer used as timecounter */ 95#define bcm_systimer_tc_read_4(reg) \ 96 bus_space_read_4(bcm_systimer_sc->bst, \ 97 bcm_systimer_sc->bsh, reg) 98 99#define bcm_systimer_tc_write_4(reg, val) \ 100 bus_space_write_4(bcm_systimer_sc->bst, \ 101 bcm_systimer_sc->bsh, reg, val) 102 103static unsigned bcm_systimer_tc_get_timecount(struct timecounter *); 104 105static delay_func bcm_systimer_delay; 106 107static struct timecounter bcm_systimer_tc = { 108 .tc_name = DEFAULT_TIMER_NAME, 109 .tc_get_timecount = bcm_systimer_tc_get_timecount, 110 .tc_poll_pps = NULL, 111 .tc_counter_mask = ~0u, 112 .tc_frequency = 0, 113 .tc_quality = 1000, 114}; 115 116static unsigned 117bcm_systimer_tc_get_timecount(struct timecounter *tc) 118{ 119 if (bcm_systimer_sc == NULL) 120 return (0); 121 122 return bcm_systimer_tc_read_4(SYSTIMER_CLO); 123} 124 125static int 126bcm_systimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 127{ 128 struct systimer *st = et->et_priv; 129 uint32_t clo, clo1; 130 uint32_t count; 131 register_t s; 132 133 if (first != 0) { 134 135 count = ((uint32_t)et->et_frequency * first) >> 32; 136 137 s = intr_disable(); 138 clo = bcm_systimer_tc_read_4(SYSTIMER_CLO); 139restart: 140 clo += count; 141 /* 142 * Clear pending interrupts 143 */ 144 bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index)); 145 bcm_systimer_tc_write_4(SYSTIMER_C0 + st->index*4, clo); 146 clo1 = bcm_systimer_tc_read_4(SYSTIMER_CLO); 147 if ((int32_t)(clo1 - clo) >= 0) { 148 count *= 2; 149 clo = clo1; 150 goto restart; 151 } 152 st->enabled = 1; 153 intr_restore(s); 154 155 return (0); 156 } 157 158 return (EINVAL); 159} 160 161static int 162bcm_systimer_stop(struct eventtimer *et) 163{ 164 struct systimer *st = et->et_priv; 165 st->enabled = 0; 166 167 return (0); 168} 169 170static int 171bcm_systimer_intr(void *arg) 172{ 173 struct systimer *st = (struct systimer *)arg; 174 uint32_t cs; 175 176 cs = bcm_systimer_tc_read_4(SYSTIMER_CS); 177 if ((cs & (1 << st->index)) == 0) 178 return (FILTER_STRAY); 179 180 /* ACK interrupt */ 181 bcm_systimer_tc_write_4(SYSTIMER_CS, (1 << st->index)); 182 if (st->enabled) { 183 if (st->et.et_active) { 184 st->et.et_event_cb(&st->et, st->et.et_arg); 185 } 186 } 187 188 return (FILTER_HANDLED); 189} 190 191static int 192bcm_systimer_probe(device_t dev) 193{ 194 195 if (!ofw_bus_status_okay(dev)) 196 return (ENXIO); 197 198 if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-system-timer")) { 199 device_set_desc(dev, "BCM2835 System Timer"); 200 return (BUS_PROBE_DEFAULT); 201 } 202 203 return (ENXIO); 204} 205 206static int 207bcm_systimer_attach(device_t dev) 208{ 209 struct bcm_systimer_softc *sc = device_get_softc(dev); 210 int err; 211 int rid = 0; 212 213 if (bcm_systimer_sc != NULL) 214 return (EINVAL); 215 216 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 217 if (sc->mem_res == NULL) { 218 device_printf(dev, "could not allocate memory resource\n"); 219 return (ENXIO); 220 } 221 222 sc->bst = rman_get_bustag(sc->mem_res); 223 sc->bsh = rman_get_bushandle(sc->mem_res); 224 225 /* Request the IRQ resources */ 226 err = bus_alloc_resources(dev, bcm_systimer_irq_spec, 227 sc->irq_res); 228 if (err) { 229 device_printf(dev, "Error: could not allocate irq resources\n"); 230 return (ENXIO); 231 } 232 233 /* TODO: get frequency from FDT */ 234 sc->sysclk_freq = DEFAULT_FREQUENCY; 235 236 /* Setup and enable the timer */ 237 if (bus_setup_intr(dev, sc->irq_res[DEFAULT_TIMER], INTR_TYPE_CLK, 238 bcm_systimer_intr, NULL, &sc->st[DEFAULT_TIMER], 239 &sc->intr_hl[DEFAULT_TIMER]) != 0) { 240 bus_release_resources(dev, bcm_systimer_irq_spec, 241 sc->irq_res); 242 device_printf(dev, "Unable to setup the clock irq handler.\n"); 243 return (ENXIO); 244 } 245 246 sc->st[DEFAULT_TIMER].index = DEFAULT_TIMER; 247 sc->st[DEFAULT_TIMER].enabled = 0; 248 sc->st[DEFAULT_TIMER].et.et_name = DEFAULT_TIMER_NAME; 249 sc->st[DEFAULT_TIMER].et.et_flags = ET_FLAGS_ONESHOT; 250 sc->st[DEFAULT_TIMER].et.et_quality = 1000; 251 sc->st[DEFAULT_TIMER].et.et_frequency = sc->sysclk_freq; 252 sc->st[DEFAULT_TIMER].et.et_min_period = 253 (MIN_PERIOD << 32) / sc->st[DEFAULT_TIMER].et.et_frequency + 1; 254 sc->st[DEFAULT_TIMER].et.et_max_period = 255 (0x7ffffffeLLU << 32) / sc->st[DEFAULT_TIMER].et.et_frequency; 256 sc->st[DEFAULT_TIMER].et.et_start = bcm_systimer_start; 257 sc->st[DEFAULT_TIMER].et.et_stop = bcm_systimer_stop; 258 sc->st[DEFAULT_TIMER].et.et_priv = &sc->st[DEFAULT_TIMER]; 259 et_register(&sc->st[DEFAULT_TIMER].et); 260 261 bcm_systimer_sc = sc; 262 263 if (device_get_unit(dev) == 0) 264 arm_set_delay(bcm_systimer_delay, sc); 265 266 bcm_systimer_tc.tc_frequency = DEFAULT_FREQUENCY; 267 tc_init(&bcm_systimer_tc); 268 269 return (0); 270} 271 272static device_method_t bcm_systimer_methods[] = { 273 DEVMETHOD(device_probe, bcm_systimer_probe), 274 DEVMETHOD(device_attach, bcm_systimer_attach), 275 { 0, 0 } 276}; 277 278static driver_t bcm_systimer_driver = { 279 "systimer", 280 bcm_systimer_methods, 281 sizeof(struct bcm_systimer_softc), 282}; 283 284static devclass_t bcm_systimer_devclass; 285 286DRIVER_MODULE(bcm_systimer, simplebus, bcm_systimer_driver, bcm_systimer_devclass, 0, 0); 287 288static void 289bcm_systimer_delay(int usec, void *arg) 290{ 291 struct bcm_systimer_softc *sc; 292 int32_t counts; 293 uint32_t first, last; 294 295 sc = (struct bcm_systimer_softc *) arg; 296 297 /* Get the number of times to count */ 298 counts = usec * (bcm_systimer_tc.tc_frequency / 1000000) + 1; 299 300 first = bcm_systimer_tc_read_4(SYSTIMER_CLO); 301 302 while (counts > 0) { 303 last = bcm_systimer_tc_read_4(SYSTIMER_CLO); 304 if (last == first) 305 continue; 306 if (last>first) { 307 counts -= (int32_t)(last - first); 308 } else { 309 counts -= (int32_t)((0xFFFFFFFF - first) + last); 310 } 311 first = last; 312 } 313} 314