1330897Seadler/*- 2330897Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330897Seadler * 4244197Sgonzo * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 5244197Sgonzo * Copyright (c) 2012 Damjan Marion <dmarion@freebsd.org> 6244197Sgonzo * All rights reserved. 7244197Sgonzo * 8244197Sgonzo * Redistribution and use in source and binary forms, with or without 9244197Sgonzo * modification, are permitted provided that the following conditions 10244197Sgonzo * are met: 11244197Sgonzo * 1. Redistributions of source code must retain the above copyright 12244197Sgonzo * notice, this list of conditions and the following disclaimer. 13244197Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 14244197Sgonzo * notice, this list of conditions and the following disclaimer in the 15244197Sgonzo * documentation and/or other materials provided with the distribution. 16244197Sgonzo * 17244197Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18244197Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19244197Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20244197Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21244197Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22244197Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23244197Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24244197Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25244197Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26244197Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27244197Sgonzo * SUCH DAMAGE. 28244197Sgonzo */ 29244197Sgonzo 30244197Sgonzo#include <sys/cdefs.h> 31244197Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/versatile/sp804.c 330897 2018-03-14 03:19:51Z eadler $"); 32244197Sgonzo 33244197Sgonzo#include <sys/param.h> 34244197Sgonzo#include <sys/systm.h> 35244197Sgonzo#include <sys/bus.h> 36244197Sgonzo#include <sys/kernel.h> 37244197Sgonzo#include <sys/module.h> 38244197Sgonzo#include <sys/malloc.h> 39244197Sgonzo#include <sys/rman.h> 40244197Sgonzo#include <sys/timeet.h> 41244197Sgonzo#include <sys/timetc.h> 42244197Sgonzo#include <sys/watchdog.h> 43244197Sgonzo#include <machine/bus.h> 44244197Sgonzo#include <machine/cpu.h> 45244197Sgonzo#include <machine/intr.h> 46244197Sgonzo 47244197Sgonzo#include <dev/ofw/openfirm.h> 48244197Sgonzo#include <dev/ofw/ofw_bus.h> 49244197Sgonzo#include <dev/ofw/ofw_bus_subr.h> 50244197Sgonzo 51244197Sgonzo#include <machine/bus.h> 52244197Sgonzo 53244197Sgonzo#define SP804_TIMER1_LOAD 0x00 54244197Sgonzo#define SP804_TIMER1_VALUE 0x04 55244197Sgonzo#define SP804_TIMER1_CONTROL 0x08 56244197Sgonzo#define TIMER_CONTROL_EN (1 << 7) 57244197Sgonzo#define TIMER_CONTROL_FREERUN (0 << 6) 58244197Sgonzo#define TIMER_CONTROL_PERIODIC (1 << 6) 59244197Sgonzo#define TIMER_CONTROL_INTREN (1 << 5) 60244197Sgonzo#define TIMER_CONTROL_DIV1 (0 << 2) 61244197Sgonzo#define TIMER_CONTROL_DIV16 (1 << 2) 62244197Sgonzo#define TIMER_CONTROL_DIV256 (2 << 2) 63244197Sgonzo#define TIMER_CONTROL_32BIT (1 << 1) 64244197Sgonzo#define TIMER_CONTROL_ONESHOT (1 << 0) 65244197Sgonzo#define SP804_TIMER1_INTCLR 0x0C 66244197Sgonzo#define SP804_TIMER1_RIS 0x10 67244197Sgonzo#define SP804_TIMER1_MIS 0x14 68244197Sgonzo#define SP804_TIMER1_BGLOAD 0x18 69244197Sgonzo#define SP804_TIMER2_LOAD 0x20 70244197Sgonzo#define SP804_TIMER2_VALUE 0x24 71244197Sgonzo#define SP804_TIMER2_CONTROL 0x28 72244197Sgonzo#define SP804_TIMER2_INTCLR 0x2C 73244197Sgonzo#define SP804_TIMER2_RIS 0x30 74244197Sgonzo#define SP804_TIMER2_MIS 0x34 75244197Sgonzo#define SP804_TIMER2_BGLOAD 0x38 76244197Sgonzo 77244197Sgonzo#define SP804_PERIPH_ID0 0xFE0 78244197Sgonzo#define SP804_PERIPH_ID1 0xFE4 79244197Sgonzo#define SP804_PERIPH_ID2 0xFE8 80244197Sgonzo#define SP804_PERIPH_ID3 0xFEC 81244197Sgonzo#define SP804_PRIMECELL_ID0 0xFF0 82244197Sgonzo#define SP804_PRIMECELL_ID1 0xFF4 83244197Sgonzo#define SP804_PRIMECELL_ID2 0xFF8 84244197Sgonzo#define SP804_PRIMECELL_ID3 0xFFC 85244197Sgonzo 86244197Sgonzo#define DEFAULT_FREQUENCY 1000000 87244197Sgonzo/* 88244197Sgonzo * QEMU seems to have problem with full frequency 89244197Sgonzo */ 90244197Sgonzo#define DEFAULT_DIVISOR 16 91244197Sgonzo#define DEFAULT_CONTROL_DIV TIMER_CONTROL_DIV16 92244197Sgonzo 93244197Sgonzostruct sp804_timer_softc { 94244197Sgonzo struct resource* mem_res; 95244197Sgonzo struct resource* irq_res; 96244197Sgonzo void* intr_hl; 97244197Sgonzo uint32_t sysclk_freq; 98244197Sgonzo bus_space_tag_t bst; 99244197Sgonzo bus_space_handle_t bsh; 100244197Sgonzo struct timecounter tc; 101244197Sgonzo bool et_enabled; 102244197Sgonzo struct eventtimer et; 103260166Szbb int timer_initialized; 104244197Sgonzo}; 105244197Sgonzo 106244197Sgonzo/* Read/Write macros for Timer used as timecounter */ 107244197Sgonzo#define sp804_timer_tc_read_4(reg) \ 108244197Sgonzo bus_space_read_4(sc->bst, sc->bsh, reg) 109244197Sgonzo 110244197Sgonzo#define sp804_timer_tc_write_4(reg, val) \ 111244197Sgonzo bus_space_write_4(sc->bst, sc->bsh, reg, val) 112244197Sgonzo 113244197Sgonzostatic unsigned sp804_timer_tc_get_timecount(struct timecounter *); 114244197Sgonzo 115244197Sgonzostatic unsigned 116244197Sgonzosp804_timer_tc_get_timecount(struct timecounter *tc) 117244197Sgonzo{ 118244197Sgonzo struct sp804_timer_softc *sc = tc->tc_priv; 119244197Sgonzo return 0xffffffff - sp804_timer_tc_read_4(SP804_TIMER1_VALUE); 120244197Sgonzo} 121244197Sgonzo 122244197Sgonzostatic int 123247463Smavsp804_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 124244197Sgonzo{ 125244197Sgonzo struct sp804_timer_softc *sc = et->et_priv; 126244197Sgonzo uint32_t count, reg; 127244197Sgonzo 128247463Smav if (first != 0) { 129244197Sgonzo sc->et_enabled = 1; 130244197Sgonzo 131247463Smav count = ((uint32_t)et->et_frequency * first) >> 32; 132244197Sgonzo 133244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER2_LOAD, count); 134244197Sgonzo reg = TIMER_CONTROL_32BIT | TIMER_CONTROL_INTREN | 135244197Sgonzo TIMER_CONTROL_PERIODIC | DEFAULT_CONTROL_DIV | 136244197Sgonzo TIMER_CONTROL_EN; 137244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg); 138244197Sgonzo 139244197Sgonzo return (0); 140244197Sgonzo } 141244197Sgonzo 142247463Smav if (period != 0) { 143244197Sgonzo panic("period"); 144244197Sgonzo } 145244197Sgonzo 146244197Sgonzo return (EINVAL); 147244197Sgonzo} 148244197Sgonzo 149244197Sgonzostatic int 150244197Sgonzosp804_timer_stop(struct eventtimer *et) 151244197Sgonzo{ 152244197Sgonzo struct sp804_timer_softc *sc = et->et_priv; 153244197Sgonzo uint32_t reg; 154244197Sgonzo 155244197Sgonzo sc->et_enabled = 0; 156244197Sgonzo reg = sp804_timer_tc_read_4(SP804_TIMER2_CONTROL); 157244197Sgonzo reg &= ~(TIMER_CONTROL_EN); 158244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg); 159244197Sgonzo 160244197Sgonzo return (0); 161244197Sgonzo} 162244197Sgonzo 163244197Sgonzostatic int 164244197Sgonzosp804_timer_intr(void *arg) 165244197Sgonzo{ 166244197Sgonzo struct sp804_timer_softc *sc = arg; 167244197Sgonzo static uint32_t prev = 0; 168244197Sgonzo uint32_t x = 0; 169244197Sgonzo 170244197Sgonzo x = sp804_timer_tc_read_4(SP804_TIMER1_VALUE); 171244197Sgonzo 172244197Sgonzo prev =x ; 173244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER2_INTCLR, 1); 174244197Sgonzo if (sc->et_enabled) { 175244197Sgonzo if (sc->et.et_active) { 176244197Sgonzo sc->et.et_event_cb(&sc->et, sc->et.et_arg); 177244197Sgonzo } 178244197Sgonzo } 179244197Sgonzo 180244197Sgonzo return (FILTER_HANDLED); 181244197Sgonzo} 182244197Sgonzo 183244197Sgonzostatic int 184244197Sgonzosp804_timer_probe(device_t dev) 185244197Sgonzo{ 186244197Sgonzo 187261410Sian if (!ofw_bus_status_okay(dev)) 188261410Sian return (ENXIO); 189261410Sian 190244197Sgonzo if (ofw_bus_is_compatible(dev, "arm,sp804")) { 191244197Sgonzo device_set_desc(dev, "SP804 System Timer"); 192244197Sgonzo return (BUS_PROBE_DEFAULT); 193244197Sgonzo } 194244197Sgonzo 195244197Sgonzo return (ENXIO); 196244197Sgonzo} 197244197Sgonzo 198244197Sgonzostatic int 199244197Sgonzosp804_timer_attach(device_t dev) 200244197Sgonzo{ 201244197Sgonzo struct sp804_timer_softc *sc = device_get_softc(dev); 202244197Sgonzo int rid = 0; 203244197Sgonzo int i; 204244197Sgonzo uint32_t id, reg; 205260166Szbb phandle_t node; 206260166Szbb pcell_t clock; 207244197Sgonzo 208244197Sgonzo sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 209244197Sgonzo if (sc->mem_res == NULL) { 210244197Sgonzo device_printf(dev, "could not allocate memory resource\n"); 211244197Sgonzo return (ENXIO); 212244197Sgonzo } 213244197Sgonzo 214244197Sgonzo sc->bst = rman_get_bustag(sc->mem_res); 215244197Sgonzo sc->bsh = rman_get_bushandle(sc->mem_res); 216244197Sgonzo 217244197Sgonzo /* Request the IRQ resources */ 218244197Sgonzo sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 219244197Sgonzo if (sc->irq_res == NULL) { 220244197Sgonzo device_printf(dev, "Error: could not allocate irq resources\n"); 221244197Sgonzo return (ENXIO); 222244197Sgonzo } 223244197Sgonzo 224244197Sgonzo sc->sysclk_freq = DEFAULT_FREQUENCY; 225260166Szbb /* Get the base clock frequency */ 226260166Szbb node = ofw_bus_get_node(dev); 227314503Sian if ((OF_getencprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) { 228314503Sian sc->sysclk_freq = clock; 229260166Szbb } 230244197Sgonzo 231244197Sgonzo /* Setup and enable the timer */ 232244197Sgonzo if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK, 233244197Sgonzo sp804_timer_intr, NULL, sc, 234244197Sgonzo &sc->intr_hl) != 0) { 235244197Sgonzo bus_release_resource(dev, SYS_RES_IRQ, rid, 236244197Sgonzo sc->irq_res); 237244197Sgonzo device_printf(dev, "Unable to setup the clock irq handler.\n"); 238244197Sgonzo return (ENXIO); 239244197Sgonzo } 240244197Sgonzo 241244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, 0); 242244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, 0); 243244197Sgonzo 244244197Sgonzo /* 245244197Sgonzo * Timer 1, timecounter 246244197Sgonzo */ 247260166Szbb sc->tc.tc_frequency = sc->sysclk_freq; 248286783Sian sc->tc.tc_name = "SP804-1"; 249244197Sgonzo sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount; 250244197Sgonzo sc->tc.tc_poll_pps = NULL; 251244197Sgonzo sc->tc.tc_counter_mask = ~0u; 252244197Sgonzo sc->tc.tc_quality = 1000; 253244197Sgonzo sc->tc.tc_priv = sc; 254244197Sgonzo 255244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER1_VALUE, 0xffffffff); 256244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER1_LOAD, 0xffffffff); 257244197Sgonzo reg = TIMER_CONTROL_PERIODIC | TIMER_CONTROL_32BIT; 258244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg); 259244197Sgonzo reg |= TIMER_CONTROL_EN; 260244197Sgonzo sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg); 261244197Sgonzo tc_init(&sc->tc); 262244197Sgonzo 263244197Sgonzo /* 264244197Sgonzo * Timer 2, event timer 265244197Sgonzo */ 266244197Sgonzo sc->et_enabled = 0; 267286783Sian sc->et.et_name = "SP804-2"; 268244197Sgonzo sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; 269244197Sgonzo sc->et.et_quality = 1000; 270244197Sgonzo sc->et.et_frequency = sc->sysclk_freq / DEFAULT_DIVISOR; 271247463Smav sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 272247463Smav sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 273244197Sgonzo sc->et.et_start = sp804_timer_start; 274244197Sgonzo sc->et.et_stop = sp804_timer_stop; 275244197Sgonzo sc->et.et_priv = sc; 276244197Sgonzo et_register(&sc->et); 277244197Sgonzo 278244197Sgonzo id = 0; 279244197Sgonzo for (i = 3; i >= 0; i--) { 280244197Sgonzo id = (id << 8) | 281244197Sgonzo (sp804_timer_tc_read_4(SP804_PERIPH_ID0 + i*4) & 0xff); 282244197Sgonzo } 283244197Sgonzo 284244197Sgonzo device_printf(dev, "peripheral ID: %08x\n", id); 285244197Sgonzo 286244197Sgonzo id = 0; 287244197Sgonzo for (i = 3; i >= 0; i--) { 288244197Sgonzo id = (id << 8) | 289244197Sgonzo (sp804_timer_tc_read_4(SP804_PRIMECELL_ID0 + i*4) & 0xff); 290244197Sgonzo } 291244197Sgonzo 292244197Sgonzo device_printf(dev, "PrimeCell ID: %08x\n", id); 293244197Sgonzo 294260166Szbb sc->timer_initialized = 1; 295260166Szbb 296244197Sgonzo return (0); 297244197Sgonzo} 298244197Sgonzo 299244197Sgonzostatic device_method_t sp804_timer_methods[] = { 300244197Sgonzo DEVMETHOD(device_probe, sp804_timer_probe), 301244197Sgonzo DEVMETHOD(device_attach, sp804_timer_attach), 302244197Sgonzo { 0, 0 } 303244197Sgonzo}; 304244197Sgonzo 305244197Sgonzostatic driver_t sp804_timer_driver = { 306244197Sgonzo "timer", 307244197Sgonzo sp804_timer_methods, 308244197Sgonzo sizeof(struct sp804_timer_softc), 309244197Sgonzo}; 310244197Sgonzo 311244197Sgonzostatic devclass_t sp804_timer_devclass; 312244197Sgonzo 313244197SgonzoDRIVER_MODULE(sp804_timer, simplebus, sp804_timer_driver, sp804_timer_devclass, 0, 0); 314244197Sgonzo 315244197Sgonzovoid 316244197SgonzoDELAY(int usec) 317244197Sgonzo{ 318244197Sgonzo int32_t counts; 319244197Sgonzo uint32_t first, last; 320244197Sgonzo device_t timer_dev; 321244197Sgonzo struct sp804_timer_softc *sc; 322260166Szbb int timer_initialized = 0; 323244197Sgonzo 324244197Sgonzo timer_dev = devclass_get_device(sp804_timer_devclass, 0); 325244197Sgonzo 326260166Szbb if (timer_dev) { 327260166Szbb sc = device_get_softc(timer_dev); 328260166Szbb 329260166Szbb if (sc) 330260166Szbb timer_initialized = sc->timer_initialized; 331260166Szbb } 332260166Szbb 333260166Szbb if (!timer_initialized) { 334244197Sgonzo /* 335244197Sgonzo * Timer is not initialized yet 336244197Sgonzo */ 337244197Sgonzo for (; usec > 0; usec--) 338244197Sgonzo for (counts = 200; counts > 0; counts--) 339244197Sgonzo /* Prevent gcc from optimizing out the loop */ 340244197Sgonzo cpufunc_nullop(); 341244197Sgonzo return; 342244197Sgonzo } 343244197Sgonzo 344244197Sgonzo /* Get the number of times to count */ 345244197Sgonzo counts = usec * ((sc->tc.tc_frequency / 1000000) + 1); 346244197Sgonzo 347244197Sgonzo first = sp804_timer_tc_get_timecount(&sc->tc); 348244197Sgonzo 349244197Sgonzo while (counts > 0) { 350244197Sgonzo last = sp804_timer_tc_get_timecount(&sc->tc); 351244197Sgonzo if (last == first) 352244197Sgonzo continue; 353244197Sgonzo if (last>first) { 354244197Sgonzo counts -= (int32_t)(last - first); 355244197Sgonzo } else { 356244197Sgonzo counts -= (int32_t)((0xFFFFFFFF - first) + last); 357244197Sgonzo } 358244197Sgonzo first = last; 359244197Sgonzo } 360244197Sgonzo} 361