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@gmail.com>
    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.0/sys/arm/allwinner/timer.c 254056 2013-08-07 11:07:56Z 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/frame.h>
   43 #include <machine/intr.h>
   44 
   45 #include <dev/fdt/fdt_common.h>
   46 #include <dev/ofw/openfirm.h>
   47 #include <dev/ofw/ofw_bus.h>
   48 #include <dev/ofw/ofw_bus_subr.h>
   49 
   50 #include <machine/bus.h>
   51 #include <machine/fdt.h>
   52 
   53 #include <sys/kdb.h>
   54 
   55 #include "a20/a20_cpu_cfg.h"
   56 
   57 /**
   58  * Timer registers addr
   59  *
   60  */
   61 #define SW_TIMER_IRQ_EN_REG     0x00
   62 #define SW_TIMER_IRQ_STA_REG    0x04
   63 #define SW_TIMER0_CTRL_REG      0x10
   64 #define SW_TIMER0_INT_VALUE_REG 0x14
   65 #define SW_TIMER0_CUR_VALUE_REG 0x18
   66 
   67 #define SW_COUNTER64LO_REG      0xa4
   68 #define SW_COUNTER64HI_REG      0xa8
   69 #define CNT64_CTRL_REG          0xa0
   70 
   71 #define CNT64_RL_EN             0x02 /* read latch enable */
   72 
   73 #define TIMER_ENABLE            (1<<0)
   74 #define TIMER_AUTORELOAD        (1<<1)
   75 #define TIMER_OSC24M            (1<<2) /* oscillator = 24mhz */
   76 #define TIMER_PRESCALAR         (4<<4) /* prescalar = 16 */
   77 
   78 #define SYS_TIMER_CLKSRC        24000000 /* clock source */
   79 
   80 struct a10_timer_softc {
   81         device_t        sc_dev;
   82         struct resource *res[2];
   83         bus_space_tag_t sc_bst;
   84         bus_space_handle_t sc_bsh;
   85         void            *sc_ih;         /* interrupt handler */
   86         uint32_t        sc_period;
   87         uint32_t        timer0_freq;
   88         struct eventtimer et;
   89         uint8_t         sc_timer_type;  /* 0 for A10, 1 for A20 */
   90 };
   91 
   92 int a10_timer_get_timerfreq(struct a10_timer_softc *);
   93 
   94 #define timer_read_4(sc, reg)   \
   95         bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg)
   96 #define timer_write_4(sc, reg, val)     \
   97         bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val)
   98 
   99 static u_int    a10_timer_get_timecount(struct timecounter *);
  100 static int      a10_timer_timer_start(struct eventtimer *,
  101     sbintime_t first, sbintime_t period);
  102 static int      a10_timer_timer_stop(struct eventtimer *);
  103 
  104 static uint64_t timer_read_counter64(void);
  105 
  106 static int a10_timer_initialized = 0;
  107 static int a10_timer_hardclock(void *);
  108 static int a10_timer_probe(device_t);
  109 static int a10_timer_attach(device_t);
  110 
  111 static struct timecounter a10_timer_timecounter = {
  112         .tc_name           = "a10_timer timer0",
  113         .tc_get_timecount  = a10_timer_get_timecount,
  114         .tc_counter_mask   = ~0u,
  115         .tc_frequency      = 0,
  116         .tc_quality        = 1000,
  117 };
  118 
  119 struct a10_timer_softc *a10_timer_sc = NULL;
  120 
  121 static struct resource_spec a10_timer_spec[] = {
  122         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  123         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  124         { -1, 0 }
  125 };
  126 
  127 static uint64_t
  128 timer_read_counter64(void)
  129 {
  130         uint32_t lo, hi;
  131 
  132         /* In case of A20 get appropriate counter info */
  133         if (a10_timer_sc->sc_timer_type)
  134                 return (a20_read_counter64());
  135 
  136         /* Latch counter, wait for it to be ready to read. */
  137         timer_write_4(a10_timer_sc, CNT64_CTRL_REG, CNT64_RL_EN);
  138         while (timer_read_4(a10_timer_sc, CNT64_CTRL_REG) & CNT64_RL_EN)
  139                 continue;
  140 
  141         hi = timer_read_4(a10_timer_sc, SW_COUNTER64HI_REG);
  142         lo = timer_read_4(a10_timer_sc, SW_COUNTER64LO_REG);
  143 
  144         return (((uint64_t)hi << 32) | lo);
  145 }
  146 
  147 static int
  148 a10_timer_probe(device_t dev)
  149 {
  150         struct a10_timer_softc *sc;
  151 
  152         sc = device_get_softc(dev);
  153 
  154         if (ofw_bus_is_compatible(dev, "allwinner,sun4i-timer"))
  155                 sc->sc_timer_type = 0;
  156         else if (ofw_bus_is_compatible(dev, "allwinner,sun7i-timer"))
  157                 sc->sc_timer_type = 1;
  158         else
  159                 return (ENXIO);
  160 
  161         device_set_desc(dev, "Allwinner A10/A20 timer");
  162         return (BUS_PROBE_DEFAULT);
  163 }
  164 
  165 static int
  166 a10_timer_attach(device_t dev)
  167 {
  168         struct a10_timer_softc *sc;
  169         int err;
  170         uint32_t val;
  171 
  172         sc = device_get_softc(dev);
  173 
  174         if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) {
  175                 device_printf(dev, "could not allocate resources\n");
  176                 return (ENXIO);
  177         }
  178 
  179         sc->sc_dev = dev;
  180         sc->sc_bst = rman_get_bustag(sc->res[0]);
  181         sc->sc_bsh = rman_get_bushandle(sc->res[0]);
  182 
  183         /* Setup and enable the timer interrupt */
  184         err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_hardclock,
  185             NULL, sc, &sc->sc_ih);
  186         if (err != 0) {
  187                 bus_release_resources(dev, a10_timer_spec, sc->res);
  188                 device_printf(dev, "Unable to setup the clock irq handler, "
  189                     "err = %d\n", err);
  190                 return (ENXIO);
  191         }
  192 
  193         /* Set clock source to OSC24M, 16 pre-division */
  194         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  195         val |= TIMER_PRESCALAR | TIMER_OSC24M;
  196         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  197 
  198         /* Enable timer0 */
  199         val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG);
  200         val |= TIMER_ENABLE;
  201         timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val);
  202 
  203         sc->timer0_freq = SYS_TIMER_CLKSRC;
  204 
  205         /* Set desired frequency in event timer and timecounter */
  206         sc->et.et_frequency = sc->timer0_freq;
  207         sc->et.et_name = "a10_timer Eventtimer";
  208         sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
  209         sc->et.et_quality = 1000;
  210         sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
  211         sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
  212         sc->et.et_start = a10_timer_timer_start;
  213         sc->et.et_stop = a10_timer_timer_stop;
  214         sc->et.et_priv = sc;
  215         et_register(&sc->et);
  216 
  217         if (device_get_unit(dev) == 0)
  218                 a10_timer_sc = sc;
  219 
  220         a10_timer_timecounter.tc_frequency = sc->timer0_freq;
  221         tc_init(&a10_timer_timecounter);
  222 
  223         if (bootverbose) {
  224                 device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz);
  225 
  226                 device_printf(sc->sc_dev, "event timer clock frequency %u\n", 
  227                     sc->timer0_freq);
  228                 device_printf(sc->sc_dev, "timecounter clock frequency %lld\n", 
  229                     a10_timer_timecounter.tc_frequency);
  230         }
  231 
  232         a10_timer_initialized = 1;
  233 
  234         return (0);
  235 }
  236 
  237 static int
  238 a10_timer_timer_start(struct eventtimer *et, sbintime_t first,
  239     sbintime_t period)
  240 {
  241         struct a10_timer_softc *sc;
  242         uint32_t count;
  243         uint32_t val;
  244 
  245         sc = (struct a10_timer_softc *)et->et_priv;
  246 
  247         if (period != 0)
  248                 sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
  249         else
  250                 sc->sc_period = 0;
  251         if (first != 0)
  252                 count = ((uint32_t)et->et_frequency * first) >> 32;
  253         else
  254                 count = sc->sc_period;
  255 
  256         /* Update timer values */
  257         timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, sc->sc_period);
  258         timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, count);
  259 
  260         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  261         if (period != 0) {
  262                 /* periodic */
  263                 val |= TIMER_AUTORELOAD;
  264         } else {
  265                 /* oneshot */
  266                 val &= ~TIMER_AUTORELOAD;
  267         }
  268         /* Enable timer0 */
  269         val |= TIMER_ENABLE;
  270         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  271 
  272         return (0);
  273 }
  274 
  275 static int
  276 a10_timer_timer_stop(struct eventtimer *et)
  277 {
  278         struct a10_timer_softc *sc;
  279         uint32_t val;
  280 
  281         sc = (struct a10_timer_softc *)et->et_priv;
  282 
  283         /* Disable timer0 */
  284         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  285         val &= ~TIMER_ENABLE;
  286         timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  287 
  288         sc->sc_period = 0;
  289 
  290         return (0);
  291 }
  292 
  293 int
  294 a10_timer_get_timerfreq(struct a10_timer_softc *sc)
  295 {
  296         return (sc->timer0_freq);
  297 }
  298 
  299 void
  300 cpu_initclocks(void)
  301 {
  302         cpu_initclocks_bsp();
  303 }
  304 
  305 static int
  306 a10_timer_hardclock(void *arg)
  307 {
  308         struct a10_timer_softc *sc;
  309         uint32_t val;
  310 
  311         sc = (struct a10_timer_softc *)arg;
  312 
  313         /* Clear interrupt pending bit. */
  314         timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1);
  315 
  316         val = timer_read_4(sc, SW_TIMER0_CTRL_REG);
  317         /*
  318          * Disabled autoreload and sc_period > 0 means 
  319          * timer_start was called with non NULL first value.
  320          * Now we will set periodic timer with the given period 
  321          * value.
  322          */
  323         if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
  324                 /* Update timer */
  325                 timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, sc->sc_period);
  326 
  327                 /* Make periodic and enable */
  328                 val |= TIMER_AUTORELOAD | TIMER_ENABLE;
  329                 timer_write_4(sc, SW_TIMER0_CTRL_REG, val);
  330         }
  331 
  332         if (sc->et.et_active)
  333                 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  334 
  335         return (FILTER_HANDLED);
  336 }
  337 
  338 u_int
  339 a10_timer_get_timecount(struct timecounter *tc)
  340 {
  341 
  342         if (a10_timer_sc == NULL)
  343                 return (0);
  344 
  345         return ((u_int)timer_read_counter64());
  346 }
  347 
  348 static device_method_t a10_timer_methods[] = {
  349         DEVMETHOD(device_probe,         a10_timer_probe),
  350         DEVMETHOD(device_attach,        a10_timer_attach),
  351 
  352         DEVMETHOD_END
  353 };
  354 
  355 static driver_t a10_timer_driver = {
  356         "a10_timer",
  357         a10_timer_methods,
  358         sizeof(struct a10_timer_softc),
  359 };
  360 
  361 static devclass_t a10_timer_devclass;
  362 
  363 DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0);
  364 
  365 void
  366 DELAY(int usec)
  367 {
  368         uint32_t counter;
  369         uint64_t end, now;
  370 
  371         if (!a10_timer_initialized) {
  372                 for (; usec > 0; usec--)
  373                         for (counter = 50; counter > 0; counter--)
  374                                 cpufunc_nullop();
  375                 return;
  376         }
  377 
  378         now = timer_read_counter64();
  379         end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1);
  380 
  381         while (now < end)
  382                 now = timer_read_counter64();
  383 }
  384 

Cache object: 6af8111379857bceca258b306af458f2


[ 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.