13da59838SAndrew Turner /*- 23da59838SAndrew Turner * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 33da59838SAndrew Turner * 43da59838SAndrew Turner * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org> 53da59838SAndrew Turner * Copyright (c) 2012 Damjan Marion <dmarion@freebsd.org> 63da59838SAndrew Turner * All rights reserved. 73da59838SAndrew Turner * 83da59838SAndrew Turner * Redistribution and use in source and binary forms, with or without 93da59838SAndrew Turner * modification, are permitted provided that the following conditions 103da59838SAndrew Turner * are met: 113da59838SAndrew Turner * 1. Redistributions of source code must retain the above copyright 123da59838SAndrew Turner * notice, this list of conditions and the following disclaimer. 133da59838SAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright 143da59838SAndrew Turner * notice, this list of conditions and the following disclaimer in the 153da59838SAndrew Turner * documentation and/or other materials provided with the distribution. 163da59838SAndrew Turner * 173da59838SAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 183da59838SAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193da59838SAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203da59838SAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213da59838SAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223da59838SAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233da59838SAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243da59838SAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253da59838SAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263da59838SAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273da59838SAndrew Turner * SUCH DAMAGE. 283da59838SAndrew Turner */ 293da59838SAndrew Turner 303da59838SAndrew Turner #include <sys/cdefs.h> 313da59838SAndrew Turner __FBSDID("$FreeBSD$"); 323da59838SAndrew Turner 333da59838SAndrew Turner #include <sys/param.h> 343da59838SAndrew Turner #include <sys/systm.h> 353da59838SAndrew Turner #include <sys/bus.h> 363da59838SAndrew Turner #include <sys/kernel.h> 373da59838SAndrew Turner #include <sys/module.h> 383da59838SAndrew Turner #include <sys/malloc.h> 393da59838SAndrew Turner 403da59838SAndrew Turner #include <sys/timeet.h> 413da59838SAndrew Turner #include <sys/timetc.h> 423da59838SAndrew Turner #include <sys/watchdog.h> 433da59838SAndrew Turner #include <machine/bus.h> 443da59838SAndrew Turner #include <machine/cpu.h> 453da59838SAndrew Turner #include <machine/intr.h> 463da59838SAndrew Turner 473da59838SAndrew Turner #include <machine/machdep.h> /* For arm_set_delay */ 483da59838SAndrew Turner 493da59838SAndrew Turner #include <dev/ofw/openfirm.h> 503da59838SAndrew Turner #include <dev/ofw/ofw_bus.h> 513da59838SAndrew Turner #include <dev/ofw/ofw_bus_subr.h> 523da59838SAndrew Turner 533da59838SAndrew Turner #include <machine/bus.h> 543da59838SAndrew Turner 553da59838SAndrew Turner #define SP804_TIMER1_LOAD 0x00 563da59838SAndrew Turner #define SP804_TIMER1_VALUE 0x04 573da59838SAndrew Turner #define SP804_TIMER1_CONTROL 0x08 583da59838SAndrew Turner #define TIMER_CONTROL_EN (1 << 7) 593da59838SAndrew Turner #define TIMER_CONTROL_FREERUN (0 << 6) 603da59838SAndrew Turner #define TIMER_CONTROL_PERIODIC (1 << 6) 613da59838SAndrew Turner #define TIMER_CONTROL_INTREN (1 << 5) 623da59838SAndrew Turner #define TIMER_CONTROL_DIV1 (0 << 2) 633da59838SAndrew Turner #define TIMER_CONTROL_DIV16 (1 << 2) 643da59838SAndrew Turner #define TIMER_CONTROL_DIV256 (2 << 2) 653da59838SAndrew Turner #define TIMER_CONTROL_32BIT (1 << 1) 663da59838SAndrew Turner #define TIMER_CONTROL_ONESHOT (1 << 0) 673da59838SAndrew Turner #define SP804_TIMER1_INTCLR 0x0C 683da59838SAndrew Turner #define SP804_TIMER1_RIS 0x10 693da59838SAndrew Turner #define SP804_TIMER1_MIS 0x14 703da59838SAndrew Turner #define SP804_TIMER1_BGLOAD 0x18 713da59838SAndrew Turner #define SP804_TIMER2_LOAD 0x20 723da59838SAndrew Turner #define SP804_TIMER2_VALUE 0x24 733da59838SAndrew Turner #define SP804_TIMER2_CONTROL 0x28 743da59838SAndrew Turner #define SP804_TIMER2_INTCLR 0x2C 753da59838SAndrew Turner #define SP804_TIMER2_RIS 0x30 763da59838SAndrew Turner #define SP804_TIMER2_MIS 0x34 773da59838SAndrew Turner #define SP804_TIMER2_BGLOAD 0x38 783da59838SAndrew Turner 793da59838SAndrew Turner #define SP804_PERIPH_ID0 0xFE0 803da59838SAndrew Turner #define SP804_PERIPH_ID1 0xFE4 813da59838SAndrew Turner #define SP804_PERIPH_ID2 0xFE8 823da59838SAndrew Turner #define SP804_PERIPH_ID3 0xFEC 833da59838SAndrew Turner #define SP804_PRIMECELL_ID0 0xFF0 843da59838SAndrew Turner #define SP804_PRIMECELL_ID1 0xFF4 853da59838SAndrew Turner #define SP804_PRIMECELL_ID2 0xFF8 863da59838SAndrew Turner #define SP804_PRIMECELL_ID3 0xFFC 873da59838SAndrew Turner 883da59838SAndrew Turner #define DEFAULT_FREQUENCY 1000000 893da59838SAndrew Turner /* 903da59838SAndrew Turner * QEMU seems to have problem with full frequency 913da59838SAndrew Turner */ 923da59838SAndrew Turner #define DEFAULT_DIVISOR 16 933da59838SAndrew Turner #define DEFAULT_CONTROL_DIV TIMER_CONTROL_DIV16 943da59838SAndrew Turner 953da59838SAndrew Turner struct sp804_timer_softc { 963da59838SAndrew Turner struct resource* mem_res; 973da59838SAndrew Turner struct resource* irq_res; 983da59838SAndrew Turner void* intr_hl; 993da59838SAndrew Turner uint32_t sysclk_freq; 1003da59838SAndrew Turner bus_space_tag_t bst; 1013da59838SAndrew Turner bus_space_handle_t bsh; 1023da59838SAndrew Turner struct timecounter tc; 1033da59838SAndrew Turner bool et_enabled; 1043da59838SAndrew Turner struct eventtimer et; 1053da59838SAndrew Turner int timer_initialized; 1063da59838SAndrew Turner }; 1073da59838SAndrew Turner 1083da59838SAndrew Turner /* Read/Write macros for Timer used as timecounter */ 1093da59838SAndrew Turner #define sp804_timer_tc_read_4(reg) \ 1103da59838SAndrew Turner bus_space_read_4(sc->bst, sc->bsh, reg) 1113da59838SAndrew Turner 1123da59838SAndrew Turner #define sp804_timer_tc_write_4(reg, val) \ 1133da59838SAndrew Turner bus_space_write_4(sc->bst, sc->bsh, reg, val) 1143da59838SAndrew Turner 1153da59838SAndrew Turner static unsigned sp804_timer_tc_get_timecount(struct timecounter *); 1163da59838SAndrew Turner static void sp804_timer_delay(int, void *); 1173da59838SAndrew Turner 1183da59838SAndrew Turner static unsigned 1193da59838SAndrew Turner sp804_timer_tc_get_timecount(struct timecounter *tc) 1203da59838SAndrew Turner { 1213da59838SAndrew Turner struct sp804_timer_softc *sc = tc->tc_priv; 1223da59838SAndrew Turner return 0xffffffff - sp804_timer_tc_read_4(SP804_TIMER1_VALUE); 1233da59838SAndrew Turner } 1243da59838SAndrew Turner 1253da59838SAndrew Turner static int 1263da59838SAndrew Turner sp804_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 1273da59838SAndrew Turner { 1283da59838SAndrew Turner struct sp804_timer_softc *sc = et->et_priv; 1293da59838SAndrew Turner uint32_t count, reg; 1303da59838SAndrew Turner 1313da59838SAndrew Turner if (first != 0) { 1323da59838SAndrew Turner sc->et_enabled = 1; 1333da59838SAndrew Turner 1343da59838SAndrew Turner count = ((uint32_t)et->et_frequency * first) >> 32; 1353da59838SAndrew Turner 1363da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER2_LOAD, count); 1373da59838SAndrew Turner reg = TIMER_CONTROL_32BIT | TIMER_CONTROL_INTREN | 1383da59838SAndrew Turner TIMER_CONTROL_PERIODIC | DEFAULT_CONTROL_DIV | 1393da59838SAndrew Turner TIMER_CONTROL_EN; 1403da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg); 1413da59838SAndrew Turner 1423da59838SAndrew Turner return (0); 1433da59838SAndrew Turner } 1443da59838SAndrew Turner 1453da59838SAndrew Turner if (period != 0) { 1463da59838SAndrew Turner panic("period"); 1473da59838SAndrew Turner } 1483da59838SAndrew Turner 1493da59838SAndrew Turner return (EINVAL); 1503da59838SAndrew Turner } 1513da59838SAndrew Turner 1523da59838SAndrew Turner static int 1533da59838SAndrew Turner sp804_timer_stop(struct eventtimer *et) 1543da59838SAndrew Turner { 1553da59838SAndrew Turner struct sp804_timer_softc *sc = et->et_priv; 1563da59838SAndrew Turner uint32_t reg; 1573da59838SAndrew Turner 1583da59838SAndrew Turner sc->et_enabled = 0; 1593da59838SAndrew Turner reg = sp804_timer_tc_read_4(SP804_TIMER2_CONTROL); 1603da59838SAndrew Turner reg &= ~(TIMER_CONTROL_EN); 1613da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, reg); 1623da59838SAndrew Turner 1633da59838SAndrew Turner return (0); 1643da59838SAndrew Turner } 1653da59838SAndrew Turner 1663da59838SAndrew Turner static int 1673da59838SAndrew Turner sp804_timer_intr(void *arg) 1683da59838SAndrew Turner { 1693da59838SAndrew Turner struct sp804_timer_softc *sc = arg; 1703da59838SAndrew Turner static uint32_t prev = 0; 1713da59838SAndrew Turner uint32_t x = 0; 1723da59838SAndrew Turner 1733da59838SAndrew Turner x = sp804_timer_tc_read_4(SP804_TIMER1_VALUE); 1743da59838SAndrew Turner 1753da59838SAndrew Turner prev =x ; 1763da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER2_INTCLR, 1); 1773da59838SAndrew Turner if (sc->et_enabled) { 1783da59838SAndrew Turner if (sc->et.et_active) { 1793da59838SAndrew Turner sc->et.et_event_cb(&sc->et, sc->et.et_arg); 1803da59838SAndrew Turner } 1813da59838SAndrew Turner } 1823da59838SAndrew Turner 1833da59838SAndrew Turner return (FILTER_HANDLED); 1843da59838SAndrew Turner } 1853da59838SAndrew Turner 1863da59838SAndrew Turner static int 1873da59838SAndrew Turner sp804_timer_probe(device_t dev) 1883da59838SAndrew Turner { 1893da59838SAndrew Turner 1903da59838SAndrew Turner if (!ofw_bus_status_okay(dev)) 1913da59838SAndrew Turner return (ENXIO); 1923da59838SAndrew Turner 1933da59838SAndrew Turner if (ofw_bus_is_compatible(dev, "arm,sp804")) { 1943da59838SAndrew Turner device_set_desc(dev, "SP804 System Timer"); 1953da59838SAndrew Turner return (BUS_PROBE_DEFAULT); 1963da59838SAndrew Turner } 1973da59838SAndrew Turner 1983da59838SAndrew Turner return (ENXIO); 1993da59838SAndrew Turner } 2003da59838SAndrew Turner 2013da59838SAndrew Turner static int 2023da59838SAndrew Turner sp804_timer_attach(device_t dev) 2033da59838SAndrew Turner { 2043da59838SAndrew Turner struct sp804_timer_softc *sc = device_get_softc(dev); 2053da59838SAndrew Turner int rid = 0; 2063da59838SAndrew Turner int i; 2073da59838SAndrew Turner uint32_t id, reg; 2083da59838SAndrew Turner phandle_t node; 2093da59838SAndrew Turner pcell_t clock; 2103da59838SAndrew Turner 2113da59838SAndrew Turner sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 2123da59838SAndrew Turner if (sc->mem_res == NULL) { 2133da59838SAndrew Turner device_printf(dev, "could not allocate memory resource\n"); 2143da59838SAndrew Turner return (ENXIO); 2153da59838SAndrew Turner } 2163da59838SAndrew Turner 2173da59838SAndrew Turner sc->bst = rman_get_bustag(sc->mem_res); 2183da59838SAndrew Turner sc->bsh = rman_get_bushandle(sc->mem_res); 2193da59838SAndrew Turner 2203da59838SAndrew Turner /* Request the IRQ resources */ 2213da59838SAndrew Turner sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 2223da59838SAndrew Turner if (sc->irq_res == NULL) { 2233da59838SAndrew Turner device_printf(dev, "Error: could not allocate irq resources\n"); 2243da59838SAndrew Turner return (ENXIO); 2253da59838SAndrew Turner } 2263da59838SAndrew Turner 2273da59838SAndrew Turner sc->sysclk_freq = DEFAULT_FREQUENCY; 2283da59838SAndrew Turner /* Get the base clock frequency */ 2293da59838SAndrew Turner node = ofw_bus_get_node(dev); 2303da59838SAndrew Turner if ((OF_getencprop(node, "clock-frequency", &clock, sizeof(clock))) > 0) { 2313da59838SAndrew Turner sc->sysclk_freq = clock; 2323da59838SAndrew Turner } 2333da59838SAndrew Turner 2343da59838SAndrew Turner /* Setup and enable the timer */ 2353da59838SAndrew Turner if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK, 2363da59838SAndrew Turner sp804_timer_intr, NULL, sc, 2373da59838SAndrew Turner &sc->intr_hl) != 0) { 2383da59838SAndrew Turner bus_release_resource(dev, SYS_RES_IRQ, rid, 2393da59838SAndrew Turner sc->irq_res); 2403da59838SAndrew Turner device_printf(dev, "Unable to setup the clock irq handler.\n"); 2413da59838SAndrew Turner return (ENXIO); 2423da59838SAndrew Turner } 2433da59838SAndrew Turner 2443da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, 0); 2453da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER2_CONTROL, 0); 2463da59838SAndrew Turner 2473da59838SAndrew Turner /* 2483da59838SAndrew Turner * Timer 1, timecounter 2493da59838SAndrew Turner */ 2503da59838SAndrew Turner sc->tc.tc_frequency = sc->sysclk_freq; 2513da59838SAndrew Turner sc->tc.tc_name = "SP804-1"; 2523da59838SAndrew Turner sc->tc.tc_get_timecount = sp804_timer_tc_get_timecount; 2533da59838SAndrew Turner sc->tc.tc_poll_pps = NULL; 2543da59838SAndrew Turner sc->tc.tc_counter_mask = ~0u; 2553da59838SAndrew Turner sc->tc.tc_quality = 1000; 2563da59838SAndrew Turner sc->tc.tc_priv = sc; 2573da59838SAndrew Turner 2583da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER1_VALUE, 0xffffffff); 2593da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER1_LOAD, 0xffffffff); 2603da59838SAndrew Turner reg = TIMER_CONTROL_PERIODIC | TIMER_CONTROL_32BIT; 2613da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg); 2623da59838SAndrew Turner reg |= TIMER_CONTROL_EN; 2633da59838SAndrew Turner sp804_timer_tc_write_4(SP804_TIMER1_CONTROL, reg); 2643da59838SAndrew Turner tc_init(&sc->tc); 2653da59838SAndrew Turner 2663da59838SAndrew Turner /* 2673da59838SAndrew Turner * Timer 2, event timer 2683da59838SAndrew Turner */ 2693da59838SAndrew Turner sc->et_enabled = 0; 2703da59838SAndrew Turner sc->et.et_name = "SP804-2"; 2713da59838SAndrew Turner sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; 2723da59838SAndrew Turner sc->et.et_quality = 1000; 2733da59838SAndrew Turner sc->et.et_frequency = sc->sysclk_freq / DEFAULT_DIVISOR; 2743da59838SAndrew Turner sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 2753da59838SAndrew Turner sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 2763da59838SAndrew Turner sc->et.et_start = sp804_timer_start; 2773da59838SAndrew Turner sc->et.et_stop = sp804_timer_stop; 2783da59838SAndrew Turner sc->et.et_priv = sc; 2793da59838SAndrew Turner et_register(&sc->et); 2803da59838SAndrew Turner 2813da59838SAndrew Turner id = 0; 2823da59838SAndrew Turner for (i = 3; i >= 0; i--) { 2833da59838SAndrew Turner id = (id << 8) | 2843da59838SAndrew Turner (sp804_timer_tc_read_4(SP804_PERIPH_ID0 + i*4) & 0xff); 2853da59838SAndrew Turner } 2863da59838SAndrew Turner 2873da59838SAndrew Turner device_printf(dev, "peripheral ID: %08x\n", id); 2883da59838SAndrew Turner 2893da59838SAndrew Turner id = 0; 2903da59838SAndrew Turner for (i = 3; i >= 0; i--) { 2913da59838SAndrew Turner id = (id << 8) | 2923da59838SAndrew Turner (sp804_timer_tc_read_4(SP804_PRIMECELL_ID0 + i*4) & 0xff); 2933da59838SAndrew Turner } 2943da59838SAndrew Turner 2953da59838SAndrew Turner arm_set_delay(sp804_timer_delay, sc); 2963da59838SAndrew Turner 2973da59838SAndrew Turner device_printf(dev, "PrimeCell ID: %08x\n", id); 2983da59838SAndrew Turner 2993da59838SAndrew Turner sc->timer_initialized = 1; 3003da59838SAndrew Turner 3013da59838SAndrew Turner return (0); 3023da59838SAndrew Turner } 3033da59838SAndrew Turner 3043da59838SAndrew Turner static device_method_t sp804_timer_methods[] = { 3053da59838SAndrew Turner DEVMETHOD(device_probe, sp804_timer_probe), 3063da59838SAndrew Turner DEVMETHOD(device_attach, sp804_timer_attach), 3073da59838SAndrew Turner { 0, 0 } 3083da59838SAndrew Turner }; 3093da59838SAndrew Turner 3103da59838SAndrew Turner static driver_t sp804_timer_driver = { 3113da59838SAndrew Turner "timer", 3123da59838SAndrew Turner sp804_timer_methods, 3133da59838SAndrew Turner sizeof(struct sp804_timer_softc), 3143da59838SAndrew Turner }; 3153da59838SAndrew Turner 3163da59838SAndrew Turner static devclass_t sp804_timer_devclass; 3173da59838SAndrew Turner 3183da59838SAndrew Turner DRIVER_MODULE(sp804_timer, simplebus, sp804_timer_driver, sp804_timer_devclass, 0, 0); 3193da59838SAndrew Turner 3203da59838SAndrew Turner static void 3213da59838SAndrew Turner sp804_timer_delay(int usec, void *arg) 3223da59838SAndrew Turner { 3233da59838SAndrew Turner struct sp804_timer_softc *sc = arg; 3243da59838SAndrew Turner int32_t counts; 3253da59838SAndrew Turner uint32_t first, last; 3263da59838SAndrew Turner 3273da59838SAndrew Turner /* Get the number of times to count */ 3283da59838SAndrew Turner counts = usec * ((sc->tc.tc_frequency / 1000000) + 1); 3293da59838SAndrew Turner 3303da59838SAndrew Turner first = sp804_timer_tc_get_timecount(&sc->tc); 3313da59838SAndrew Turner 3323da59838SAndrew Turner while (counts > 0) { 3333da59838SAndrew Turner last = sp804_timer_tc_get_timecount(&sc->tc); 3343da59838SAndrew Turner if (last == first) 3353da59838SAndrew Turner continue; 3363da59838SAndrew Turner if (last > first) { 3373da59838SAndrew Turner counts -= (int32_t)(last - first); 3383da59838SAndrew Turner } else { 3393da59838SAndrew Turner counts -= (int32_t)((0xFFFFFFFF - first) + last); 3403da59838SAndrew Turner } 3413da59838SAndrew Turner first = last; 3423da59838SAndrew Turner } 3433da59838SAndrew Turner } 344