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/a10_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$");
   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/intr.h>
   42 #include <machine/machdep.h>
   43 
   44 #include <dev/ofw/openfirm.h>
   45 #include <dev/ofw/ofw_bus.h>
   46 #include <dev/ofw/ofw_bus_subr.h>
   47 
   48 #include <dev/extres/clk/clk.h>
   49 
   50 #if defined(__aarch64__)
   51 #include "opt_soc.h"
   52 #else
   53 #include <arm/allwinner/aw_machdep.h>
   54 #endif
   55 
   56 /**
   57  * Timer registers addr
   58  *
   59  */
   60 #define TIMER_IRQ_EN_REG        0x00
   61 #define  TIMER_IRQ_ENABLE(x)    (1 << x)
   62 
   63 #define TIMER_IRQ_STA_REG       0x04
   64 #define  TIMER_IRQ_PENDING(x)   (1 << x)
   65 
   66 /*
   67  * On A10, A13, A20 and A31/A31s 6 timers are available
   68  */
   69 #define TIMER_CTRL_REG(x)               (0x10 + 0x10 * x)
   70 #define  TIMER_CTRL_START               (1 << 0)
   71 #define  TIMER_CTRL_AUTORELOAD          (1 << 1)
   72 #define  TIMER_CTRL_CLKSRC_MASK         (3 << 2)
   73 #define  TIMER_CTRL_OSC24M              (1 << 2)
   74 #define  TIMER_CTRL_PRESCALAR_MASK      (0x7 << 4)
   75 #define  TIMER_CTRL_PRESCALAR(x)        ((x - 1) << 4)
   76 #define  TIMER_CTRL_MODE_MASK           (1 << 7)
   77 #define  TIMER_CTRL_MODE_SINGLE         (1 << 7)
   78 #define  TIMER_CTRL_MODE_CONTINUOUS     (0 << 7)
   79 #define TIMER_INTV_REG(x)               (0x14 + 0x10 * x)
   80 #define TIMER_CURV_REG(x)               (0x18 + 0x10 * x)
   81 
   82 /* 64 bit counter, available in A10 and A13 */
   83 #define CNT64_CTRL_REG          0xa0
   84 #define  CNT64_CTRL_RL_EN       0x02 /* read latch enable */
   85 #define CNT64_LO_REG    0xa4
   86 #define CNT64_HI_REG    0xa8
   87 
   88 #define SYS_TIMER_CLKSRC        24000000 /* clock source */
   89 
   90 enum a10_timer_type {
   91         A10_TIMER = 1,
   92         A23_TIMER,
   93 };
   94 
   95 struct a10_timer_softc {
   96         device_t        sc_dev;
   97         struct resource *res[2];
   98         void            *sc_ih;         /* interrupt handler */
   99         uint32_t        sc_period;
  100         uint64_t        timer0_freq;
  101         struct eventtimer       et;
  102         enum a10_timer_type     type;
  103 };
  104 
  105 #define timer_read_4(sc, reg)   \
  106         bus_read_4(sc->res[A10_TIMER_MEMRES], reg)
  107 #define timer_write_4(sc, reg, val)     \
  108         bus_write_4(sc->res[A10_TIMER_MEMRES], reg, val)
  109 
  110 static u_int    a10_timer_get_timecount(struct timecounter *);
  111 #if defined(__arm__)
  112 static int      a10_timer_timer_start(struct eventtimer *,
  113     sbintime_t first, sbintime_t period);
  114 static int      a10_timer_timer_stop(struct eventtimer *);
  115 #endif
  116 
  117 static uint64_t timer_read_counter64(struct a10_timer_softc *sc);
  118 #if defined(__arm__)
  119 static void a10_timer_eventtimer_setup(struct a10_timer_softc *sc);
  120 #endif
  121 
  122 #if defined(__aarch64__)
  123 static void a23_timer_timecounter_setup(struct a10_timer_softc *sc);
  124 static u_int a23_timer_get_timecount(struct timecounter *tc);
  125 #endif
  126 
  127 static int a10_timer_irq(void *);
  128 static int a10_timer_probe(device_t);
  129 static int a10_timer_attach(device_t);
  130 
  131 #if defined(__arm__)
  132 static delay_func a10_timer_delay;
  133 #endif
  134 
  135 static struct timecounter a10_timer_timecounter = {
  136         .tc_name           = "a10_timer timer0",
  137         .tc_get_timecount  = a10_timer_get_timecount,
  138         .tc_counter_mask   = ~0u,
  139         .tc_frequency      = 0,
  140         .tc_quality        = 1000,
  141 };
  142 
  143 #if defined(__aarch64__)
  144 static struct timecounter a23_timer_timecounter = {
  145         .tc_name           = "a10_timer timer0",
  146         .tc_get_timecount  = a23_timer_get_timecount,
  147         .tc_counter_mask   = ~0u,
  148         .tc_frequency      = 0,
  149         /* We want it to be selected over the arm generic timecounter */
  150         .tc_quality        = 2000,
  151 };
  152 #endif
  153 
  154 #define A10_TIMER_MEMRES                0
  155 #define A10_TIMER_IRQRES                1
  156 
  157 static struct resource_spec a10_timer_spec[] = {
  158         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  159         { SYS_RES_IRQ,          0,      RF_ACTIVE },
  160         { -1, 0 }
  161 };
  162 
  163 static struct ofw_compat_data compat_data[] = {
  164         {"allwinner,sun4i-a10-timer", A10_TIMER},
  165 #if defined(__aarch64__)
  166         {"allwinner,sun8i-a23-timer", A23_TIMER},
  167 #endif
  168         {NULL, 0},
  169 };
  170 
  171 static int
  172 a10_timer_probe(device_t dev)
  173 {
  174 #if defined(__arm__)
  175         u_int soc_family;
  176 #endif
  177 
  178         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  179                 return (ENXIO);
  180 
  181 #if defined(__arm__)
  182         /* For SoC >= A10 we have the ARM Timecounter/Eventtimer */
  183         soc_family = allwinner_soc_family();
  184         if (soc_family != ALLWINNERSOC_SUN4I &&
  185             soc_family != ALLWINNERSOC_SUN5I)
  186                 return (ENXIO);
  187 #endif
  188 
  189         device_set_desc(dev, "Allwinner timer");
  190         return (BUS_PROBE_DEFAULT);
  191 }
  192 
  193 static int
  194 a10_timer_attach(device_t dev)
  195 {
  196         struct a10_timer_softc *sc;
  197         clk_t clk;
  198         int err;
  199 
  200         sc = device_get_softc(dev);
  201         sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  202 
  203         if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) {
  204                 device_printf(dev, "could not allocate resources\n");
  205                 return (ENXIO);
  206         }
  207 
  208         sc->sc_dev = dev;
  209 
  210         /* Setup and enable the timer interrupt */
  211         err = bus_setup_intr(dev, sc->res[A10_TIMER_IRQRES], INTR_TYPE_CLK,
  212             a10_timer_irq, NULL, sc, &sc->sc_ih);
  213         if (err != 0) {
  214                 bus_release_resources(dev, a10_timer_spec, sc->res);
  215                 device_printf(dev, "Unable to setup the clock irq handler, "
  216                     "err = %d\n", err);
  217                 return (ENXIO);
  218         }
  219 
  220         if (clk_get_by_ofw_index(dev, 0, 0, &clk) != 0)
  221                 sc->timer0_freq = SYS_TIMER_CLKSRC;
  222         else {
  223                 if (clk_get_freq(clk, &sc->timer0_freq) != 0) {
  224                         device_printf(dev, "Cannot get clock source frequency\n");
  225                         return (ENXIO);
  226                 }
  227         }
  228 
  229 #if defined(__arm__)
  230         a10_timer_eventtimer_setup(sc);
  231         arm_set_delay(a10_timer_delay, sc);
  232         a10_timer_timecounter.tc_priv = sc;
  233         a10_timer_timecounter.tc_frequency = sc->timer0_freq;
  234         tc_init(&a10_timer_timecounter);
  235 #elif defined(__aarch64__)
  236         a23_timer_timecounter_setup(sc);
  237 #endif
  238 
  239         if (bootverbose) {
  240                 device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz);
  241 
  242                 device_printf(sc->sc_dev, "event timer clock frequency %ju\n", 
  243                     sc->timer0_freq);
  244                 device_printf(sc->sc_dev, "timecounter clock frequency %jd\n", 
  245                     a10_timer_timecounter.tc_frequency);
  246         }
  247 
  248         return (0);
  249 }
  250 
  251 static int
  252 a10_timer_irq(void *arg)
  253 {
  254         struct a10_timer_softc *sc;
  255         uint32_t val;
  256 
  257         sc = (struct a10_timer_softc *)arg;
  258 
  259         /* Clear interrupt pending bit. */
  260         timer_write_4(sc, TIMER_IRQ_STA_REG, TIMER_IRQ_PENDING(0));
  261 
  262         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  263 
  264         /*
  265          * Disabled autoreload and sc_period > 0 means 
  266          * timer_start was called with non NULL first value.
  267          * Now we will set periodic timer with the given period 
  268          * value.
  269          */
  270         if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
  271                 /* Update timer */
  272                 timer_write_4(sc, TIMER_CURV_REG(0), sc->sc_period);
  273 
  274                 /* Make periodic and enable */
  275                 val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
  276                 timer_write_4(sc, TIMER_CTRL_REG(0), val);
  277         }
  278 
  279         if (sc->et.et_active)
  280                 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  281 
  282         return (FILTER_HANDLED);
  283 }
  284 
  285 /*
  286  * Event timer function for A10 and A13
  287  */
  288 
  289 #if defined(__arm__)
  290 static void
  291 a10_timer_eventtimer_setup(struct a10_timer_softc *sc)
  292 {
  293         uint32_t val;
  294 
  295         /* Set clock source to OSC24M, 1 pre-division, continuous mode */
  296         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  297         val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
  298         val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
  299         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  300 
  301         /* Enable timer0 */
  302         val = timer_read_4(sc, TIMER_IRQ_EN_REG);
  303         val |= TIMER_IRQ_ENABLE(0);
  304         timer_write_4(sc, TIMER_IRQ_EN_REG, val);
  305 
  306         /* Set desired frequency in event timer and timecounter */
  307         sc->et.et_frequency = sc->timer0_freq;
  308         sc->et.et_name = "a10_timer Eventtimer";
  309         sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
  310         sc->et.et_quality = 1000;
  311         sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
  312         sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
  313         sc->et.et_start = a10_timer_timer_start;
  314         sc->et.et_stop = a10_timer_timer_stop;
  315         sc->et.et_priv = sc;
  316         et_register(&sc->et);
  317 }
  318 
  319 static int
  320 a10_timer_timer_start(struct eventtimer *et, sbintime_t first,
  321     sbintime_t period)
  322 {
  323         struct a10_timer_softc *sc;
  324         uint32_t count;
  325         uint32_t val;
  326 
  327         sc = (struct a10_timer_softc *)et->et_priv;
  328 
  329         if (period != 0)
  330                 sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
  331         else
  332                 sc->sc_period = 0;
  333         if (first != 0)
  334                 count = ((uint32_t)et->et_frequency * first) >> 32;
  335         else
  336                 count = sc->sc_period;
  337 
  338         /* Update timer values */
  339         timer_write_4(sc, TIMER_INTV_REG(0), sc->sc_period);
  340         timer_write_4(sc, TIMER_CURV_REG(0), count);
  341 
  342         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  343         if (period != 0) {
  344                 /* periodic */
  345                 val |= TIMER_CTRL_AUTORELOAD;
  346         } else {
  347                 /* oneshot */
  348                 val &= ~TIMER_CTRL_AUTORELOAD;
  349         }
  350         /* Enable timer0 */
  351         val |= TIMER_IRQ_ENABLE(0);
  352         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  353 
  354         return (0);
  355 }
  356 
  357 static int
  358 a10_timer_timer_stop(struct eventtimer *et)
  359 {
  360         struct a10_timer_softc *sc;
  361         uint32_t val;
  362 
  363         sc = (struct a10_timer_softc *)et->et_priv;
  364 
  365         /* Disable timer0 */
  366         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  367         val &= ~TIMER_CTRL_START;
  368         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  369 
  370         sc->sc_period = 0;
  371 
  372         return (0);
  373 }
  374 #endif
  375 
  376 /*
  377  * Timecounter functions for A23 and above
  378  */
  379 
  380 #if defined(__aarch64__)
  381 static void
  382 a23_timer_timecounter_setup(struct a10_timer_softc *sc)
  383 {
  384         uint32_t val;
  385 
  386         /* Set clock source to OSC24M, 1 pre-division, continuous mode */
  387         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  388         val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
  389         val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
  390         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  391 
  392         /* Set reload value */
  393         timer_write_4(sc, TIMER_INTV_REG(0), ~0);
  394         val = timer_read_4(sc, TIMER_INTV_REG(0));
  395 
  396         /* Enable timer0 */
  397         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  398         val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
  399         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  400 
  401         val = timer_read_4(sc, TIMER_CURV_REG(0));
  402 
  403         a23_timer_timecounter.tc_priv = sc;
  404         a23_timer_timecounter.tc_frequency = sc->timer0_freq;
  405         tc_init(&a23_timer_timecounter);
  406 }
  407 
  408 static u_int
  409 a23_timer_get_timecount(struct timecounter *tc)
  410 {
  411         struct a10_timer_softc *sc;
  412         uint32_t val;
  413 
  414         sc = (struct a10_timer_softc *)tc->tc_priv;
  415         if (sc == NULL)
  416                 return (0);
  417 
  418         val = timer_read_4(sc, TIMER_CURV_REG(0));
  419         /* Counter count backwards */
  420         return (~0u - val);
  421 }
  422 #endif
  423 
  424 /*
  425  * Timecounter functions for A10 and A13, using the 64 bits counter
  426  */
  427 
  428 static uint64_t
  429 timer_read_counter64(struct a10_timer_softc *sc)
  430 {
  431         uint32_t lo, hi;
  432 
  433         /* Latch counter, wait for it to be ready to read. */
  434         timer_write_4(sc, CNT64_CTRL_REG, CNT64_CTRL_RL_EN);
  435         while (timer_read_4(sc, CNT64_CTRL_REG) & CNT64_CTRL_RL_EN)
  436                 continue;
  437 
  438         hi = timer_read_4(sc, CNT64_HI_REG);
  439         lo = timer_read_4(sc, CNT64_LO_REG);
  440 
  441         return (((uint64_t)hi << 32) | lo);
  442 }
  443 
  444 #if defined(__arm__)
  445 static void
  446 a10_timer_delay(int usec, void *arg)
  447 {
  448         struct a10_timer_softc *sc = arg;
  449         uint64_t end, now;
  450 
  451         now = timer_read_counter64(sc);
  452         end = now + (sc->timer0_freq / 1000000) * (usec + 1);
  453 
  454         while (now < end)
  455                 now = timer_read_counter64(sc);
  456 }
  457 #endif
  458 
  459 static u_int
  460 a10_timer_get_timecount(struct timecounter *tc)
  461 {
  462 
  463         if (tc->tc_priv == NULL)
  464                 return (0);
  465 
  466         return ((u_int)timer_read_counter64(tc->tc_priv));
  467 }
  468 
  469 static device_method_t a10_timer_methods[] = {
  470         DEVMETHOD(device_probe,         a10_timer_probe),
  471         DEVMETHOD(device_attach,        a10_timer_attach),
  472 
  473         DEVMETHOD_END
  474 };
  475 
  476 static driver_t a10_timer_driver = {
  477         "a10_timer",
  478         a10_timer_methods,
  479         sizeof(struct a10_timer_softc),
  480 };
  481 
  482 static devclass_t a10_timer_devclass;
  483 
  484 EARLY_DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0,
  485     BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);

Cache object: 4a61578f94fd7eb171c81b8a1f3f140f


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