The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/allwinner/timer.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/10.2/sys/arm/allwinner/timer.c 277113 2015-01-13 07:45:16Z ganbold $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/malloc.h>
   36 #include <sys/rman.h>
   37 #include <sys/timeet.h>
   38 #include <sys/timetc.h>
   39 #include <sys/watchdog.h>
   40 #include <machine/bus.h>
   41 #include <machine/cpu.h>
   42 #include <machine/intr.h>
   43 
   44 #include <dev/fdt/fdt_common.h>
   45 #include <dev/ofw/openfirm.h>
   46 #include <dev/ofw/ofw_bus.h>
   47 #include <dev/ofw/ofw_bus_subr.h>
   48 
   49 #include <machine/bus.h>
   50 #include <machine/fdt.h>
   51 
   52 #include <sys/kdb.h>
   53 
   54 #include "a20/a20_cpu_cfg.h"
   55 
   56 /**
   57  * Timer registers addr
   58  *
   59  */
   60 #define SW_TIMER_IRQ_EN_REG     0x00
   61 #define SW_TIMER_IRQ_STA_REG    0x04
   62 #define SW_TIMER0_CTRL_REG      0x10
   63 #define SW_TIMER0_INT_VALUE_REG 0x14
   64 #define SW_TIMER0_CUR_VALUE_REG 0x18
   65 
   66 #define SW_COUNTER64LO_REG      0xa4
   67 #define SW_COUNTER64HI_REG      0xa8
   68 #define CNT64_CTRL_REG          0xa0
   69 
   70 #define CNT64_RL_EN             0x02 /* read latch enable */
   71 
   72 #define TIMER_ENABLE            (1<<0)
   73 #define TIMER_AUTORELOAD        (1<<1)
   74 #define TIMER_OSC24M            (1<<2) /* oscillator = 24mhz */
   75 #define TIMER_PRESCALAR         (0<<4) /* prescalar = 1 */
   76 
   77 #define SYS_TIMER_CLKSRC        24000000 /* clock source */
   78 
   79 struct a10_timer_softc {
   80         device_t        sc_dev;
   81         struct resource *res[2];
   82         bus_space_tag_t sc_bst;
   83         bus_space_handle_t sc_bsh;
   84         void            *sc_ih;         /* interrupt handler */
   85         uint32_t        sc_period;
   86         uint32_t        timer0_freq;
   87         struct eventtimer et;
   88         uint8_t         sc_timer_type;  /* 0 for A10, 1 for A20 */
   89 };
   90 
   91 int a10_timer_get_timerfreq(struct a10_timer_softc *);
   92 
   93 #define timer_read_4(sc, reg)   \
   94         bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg)
   95 #define timer_write_4(sc, reg, val)     \
   96         bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val)
   97 
   98 static u_int    a10_timer_get_timecount(struct timecounter *);
   99 static int      a10_timer_timer_start(struct eventtimer *,
  100     sbintime_t first, sbintime_t period);
  101 static int      a10_timer_timer_stop(struct eventtimer *);
  102 
  103 static uint64_t timer_read_counter64(void);
  104 
  105 static int a10_timer_initialized = 0;
  106 static int a10_timer_hardclock(void *);
  107 static int a10_timer_probe(device_t);
  108 static int a10_timer_attach(device_t);
  109 
  110 static struct timecounter a10_timer_timecounter = {
  111         .tc_name           = "a10_timer timer0",
  112         .tc_get_timecount  = a10_timer_get_timecount,
  113         .tc_counter_mask   = ~0u,
  114         .tc_frequency      = 0,
  115         .tc_quality        = 1000,
  116 };
  117 
  118 struct a10_timer_softc *a10_timer_sc = NULL;
  119 
  120 static struct resource_spec a10_timer_spec[] = {
  121         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  122         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  123         { -1, 0 }
  124 };
  125 
  126 static uint64_t
  127 timer_read_counter64(void)
  128 {
  129         uint32_t lo, hi;
  130 
  131         /* In case of A20 get appropriate counter info */
  132         if (a10_timer_sc->sc_timer_type)
  133                 return (a20_read_counter64());
  134 
  135         /* Latch counter, wait for it to be ready to read. */
  136         timer_write_4(a10_timer_sc, CNT64_CTRL_REG, CNT64_RL_EN);
  137         while (timer_read_4(a10_timer_sc, CNT64_CTRL_REG) & CNT64_RL_EN)
  138                 continue;
  139 
  140         hi = timer_read_4(a10_timer_sc, SW_COUNTER64HI_REG);
  141         lo = timer_read_4(a10_timer_sc, SW_COUNTER64LO_REG);
  142 
  143         return (((uint64_t)hi << 32) | lo);
  144 }
  145 
  146 static int
  147 a10_timer_probe(device_t dev)
  148 {
  149         struct a10_timer_softc *sc;
  150 
  151         sc = device_get_softc(dev);
  152 
  153         if (ofw_bus_is_compatible(dev, "allwinner,sun4i-timer"))
  154                 sc->sc_timer_type = 0;
  155         else if (ofw_bus_is_compatible(dev, "allwinner,sun7i-timer"))
  156                 sc->sc_timer_type = 1;
  157         else
  158                 return (ENXIO);
  159 
  160         device_set_desc(dev, "Allwinner A10/A20 timer");
  161         return (BUS_PROBE_DEFAULT);
  162 }
  163 
  164 static int
  165 a10_timer_attach(device_t dev)
  166 {
  167         struct a10_timer_softc *sc;
  168         int err;
  169         uint32_t val;
  170 
  171         sc = device_get_softc(dev);
  172 
  173         if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) {
  174                 device_printf(dev, "could not allocate resources\n");
  175                 return (ENXIO);
  176         }
  177 
  178         sc->sc_dev = dev;
  179         sc->sc_bst = rman_get_bustag(sc->res[0]);
  180         sc->sc_bsh = rman_get_bushandle(sc->res[0]);
  181 
  182         /* Setup and enable the timer interrupt */
  183         err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_hardclock,
  184             NULL, sc, &sc->sc_ih);
  185         if (err != 0) {
  186                 bus_release_resources(dev, a10_timer_spec, sc->res);
  187                 device_printf(dev, "Unable to setup the clock irq handler, "
  188                     "err = %d\n", err);
  189                 return (ENXIO);
  190         }
  191 
  192         /* Set clock source to OSC24M, 16 pre-division */
  193         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  194         val |= TIMER_PRESCALAR | TIMER_OSC24M;
  195         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  196 
  197         /* Enable timer0 */
  198         val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG);
  199         val |= TIMER_ENABLE;
  200         timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val);
  201 
  202         sc->timer0_freq = SYS_TIMER_CLKSRC;
  203 
  204         /* Set desired frequency in event timer and timecounter */
  205         sc->et.et_frequency = sc->timer0_freq;
  206         sc->et.et_name = "a10_timer Eventtimer";
  207         sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
  208         sc->et.et_quality = 1000;
  209         sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
  210         sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
  211         sc->et.et_start = a10_timer_timer_start;
  212         sc->et.et_stop = a10_timer_timer_stop;
  213         sc->et.et_priv = sc;
  214         et_register(&sc->et);
  215 
  216         if (device_get_unit(dev) == 0)
  217                 a10_timer_sc = sc;
  218 
  219         a10_timer_timecounter.tc_frequency = sc->timer0_freq;
  220         tc_init(&a10_timer_timecounter);
  221 
  222         if (bootverbose) {
  223                 device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz);
  224 
  225                 device_printf(sc->sc_dev, "event timer clock frequency %u\n", 
  226                     sc->timer0_freq);
  227                 device_printf(sc->sc_dev, "timecounter clock frequency %lld\n", 
  228                     a10_timer_timecounter.tc_frequency);
  229         }
  230 
  231         a10_timer_initialized = 1;
  232 
  233         return (0);
  234 }
  235 
  236 static int
  237 a10_timer_timer_start(struct eventtimer *et, sbintime_t first,
  238     sbintime_t period)
  239 {
  240         struct a10_timer_softc *sc;
  241         uint32_t count;
  242         uint32_t val;
  243 
  244         sc = (struct a10_timer_softc *)et->et_priv;
  245 
  246         if (period != 0)
  247                 sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
  248         else
  249                 sc->sc_period = 0;
  250         if (first != 0)
  251                 count = ((uint32_t)et->et_frequency * first) >> 32;
  252         else
  253                 count = sc->sc_period;
  254 
  255         /* Update timer values */
  256         timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, sc->sc_period);
  257         timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, count);
  258 
  259         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  260         if (period != 0) {
  261                 /* periodic */
  262                 val |= TIMER_AUTORELOAD;
  263         } else {
  264                 /* oneshot */
  265                 val &= ~TIMER_AUTORELOAD;
  266         }
  267         /* Enable timer0 */
  268         val |= TIMER_ENABLE;
  269         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  270 
  271         return (0);
  272 }
  273 
  274 static int
  275 a10_timer_timer_stop(struct eventtimer *et)
  276 {
  277         struct a10_timer_softc *sc;
  278         uint32_t val;
  279 
  280         sc = (struct a10_timer_softc *)et->et_priv;
  281 
  282         /* Disable timer0 */
  283         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  284         val &= ~TIMER_ENABLE;
  285         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  286 
  287         sc->sc_period = 0;
  288 
  289         return (0);
  290 }
  291 
  292 int
  293 a10_timer_get_timerfreq(struct a10_timer_softc *sc)
  294 {
  295         return (sc->timer0_freq);
  296 }
  297 
  298 static int
  299 a10_timer_hardclock(void *arg)
  300 {
  301         struct a10_timer_softc *sc;
  302         uint32_t val;
  303 
  304         sc = (struct a10_timer_softc *)arg;
  305 
  306         /* Clear interrupt pending bit. */
  307         timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1);
  308 
  309         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  310         /*
  311          * Disabled autoreload and sc_period > 0 means 
  312          * timer_start was called with non NULL first value.
  313          * Now we will set periodic timer with the given period 
  314          * value.
  315          */
  316         if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
  317                 /* Update timer */
  318                 timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, sc->sc_period);
  319 
  320                 /* Make periodic and enable */
  321                 val |= TIMER_AUTORELOAD | TIMER_ENABLE;
  322                 timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  323         }
  324 
  325         if (sc->et.et_active)
  326                 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  327 
  328         return (FILTER_HANDLED);
  329 }
  330 
  331 u_int
  332 a10_timer_get_timecount(struct timecounter *tc)
  333 {
  334 
  335         if (a10_timer_sc == NULL)
  336                 return (0);
  337 
  338         return ((u_int)timer_read_counter64());
  339 }
  340 
  341 static device_method_t a10_timer_methods[] = {
  342         DEVMETHOD(device_probe,         a10_timer_probe),
  343         DEVMETHOD(device_attach,        a10_timer_attach),
  344 
  345         DEVMETHOD_END
  346 };
  347 
  348 static driver_t a10_timer_driver = {
  349         "a10_timer",
  350         a10_timer_methods,
  351         sizeof(struct a10_timer_softc),
  352 };
  353 
  354 static devclass_t a10_timer_devclass;
  355 
  356 DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0);
  357 
  358 void
  359 DELAY(int usec)
  360 {
  361         uint32_t counter;
  362         uint64_t end, now;
  363 
  364         if (!a10_timer_initialized) {
  365                 for (; usec > 0; usec--)
  366                         for (counter = 50; counter > 0; counter--)
  367                                 cpufunc_nullop();
  368                 return;
  369         }
  370 
  371         now = timer_read_counter64();
  372         end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1);
  373 
  374         while (now < end)
  375                 now = timer_read_counter64();
  376 }
  377 

Cache object: 57c77e8a2e2cc37b8afa1da8c185f40f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.