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         struct a10_timer_softc *sc;
  175 #if defined(__arm__)
  176         u_int soc_family;
  177 #endif
  178 
  179         sc = device_get_softc(dev);
  180 
  181         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  182                 return (ENXIO);
  183 
  184 #if defined(__arm__)
  185         /* For SoC >= A10 we have the ARM Timecounter/Eventtimer */
  186         soc_family = allwinner_soc_family();
  187         if (soc_family != ALLWINNERSOC_SUN4I &&
  188             soc_family != ALLWINNERSOC_SUN5I)
  189                 return (ENXIO);
  190 #endif
  191 
  192         device_set_desc(dev, "Allwinner timer");
  193         return (BUS_PROBE_DEFAULT);
  194 }
  195 
  196 static int
  197 a10_timer_attach(device_t dev)
  198 {
  199         struct a10_timer_softc *sc;
  200         clk_t clk;
  201         int err;
  202 
  203         sc = device_get_softc(dev);
  204         sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  205 
  206         if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) {
  207                 device_printf(dev, "could not allocate resources\n");
  208                 return (ENXIO);
  209         }
  210 
  211         sc->sc_dev = dev;
  212 
  213         /* Setup and enable the timer interrupt */
  214         err = bus_setup_intr(dev, sc->res[A10_TIMER_IRQRES], INTR_TYPE_CLK,
  215             a10_timer_irq, NULL, sc, &sc->sc_ih);
  216         if (err != 0) {
  217                 bus_release_resources(dev, a10_timer_spec, sc->res);
  218                 device_printf(dev, "Unable to setup the clock irq handler, "
  219                     "err = %d\n", err);
  220                 return (ENXIO);
  221         }
  222 
  223         if (clk_get_by_ofw_index(dev, 0, 0, &clk) != 0)
  224                 sc->timer0_freq = SYS_TIMER_CLKSRC;
  225         else {
  226                 if (clk_get_freq(clk, &sc->timer0_freq) != 0) {
  227                         device_printf(dev, "Cannot get clock source frequency\n");
  228                         return (ENXIO);
  229                 }
  230         }
  231 
  232 #if defined(__arm__)
  233         a10_timer_eventtimer_setup(sc);
  234         arm_set_delay(a10_timer_delay, sc);
  235         a10_timer_timecounter.tc_priv = sc;
  236         a10_timer_timecounter.tc_frequency = sc->timer0_freq;
  237         tc_init(&a10_timer_timecounter);
  238 #elif defined(__aarch64__)
  239         a23_timer_timecounter_setup(sc);
  240 #endif
  241 
  242         if (bootverbose) {
  243                 device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz);
  244 
  245                 device_printf(sc->sc_dev, "event timer clock frequency %ju\n", 
  246                     sc->timer0_freq);
  247                 device_printf(sc->sc_dev, "timecounter clock frequency %jd\n", 
  248                     a10_timer_timecounter.tc_frequency);
  249         }
  250 
  251         return (0);
  252 }
  253 
  254 static int
  255 a10_timer_irq(void *arg)
  256 {
  257         struct a10_timer_softc *sc;
  258         uint32_t val;
  259 
  260         sc = (struct a10_timer_softc *)arg;
  261 
  262         /* Clear interrupt pending bit. */
  263         timer_write_4(sc, TIMER_IRQ_STA_REG, TIMER_IRQ_PENDING(0));
  264 
  265         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  266 
  267         /*
  268          * Disabled autoreload and sc_period > 0 means 
  269          * timer_start was called with non NULL first value.
  270          * Now we will set periodic timer with the given period 
  271          * value.
  272          */
  273         if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
  274                 /* Update timer */
  275                 timer_write_4(sc, TIMER_CURV_REG(0), sc->sc_period);
  276 
  277                 /* Make periodic and enable */
  278                 val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
  279                 timer_write_4(sc, TIMER_CTRL_REG(0), val);
  280         }
  281 
  282         if (sc->et.et_active)
  283                 sc->et.et_event_cb(&sc->et, sc->et.et_arg);
  284 
  285         return (FILTER_HANDLED);
  286 }
  287 
  288 /*
  289  * Event timer function for A10 and A13
  290  */
  291 
  292 #if defined(__arm__)
  293 static void
  294 a10_timer_eventtimer_setup(struct a10_timer_softc *sc)
  295 {
  296         uint32_t val;
  297 
  298         /* Set clock source to OSC24M, 1 pre-division, continuous mode */
  299         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  300         val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
  301         val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
  302         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  303 
  304         /* Enable timer0 */
  305         val = timer_read_4(sc, TIMER_IRQ_EN_REG);
  306         val |= TIMER_IRQ_ENABLE(0);
  307         timer_write_4(sc, TIMER_IRQ_EN_REG, val);
  308 
  309         /* Set desired frequency in event timer and timecounter */
  310         sc->et.et_frequency = sc->timer0_freq;
  311         sc->et.et_name = "a10_timer Eventtimer";
  312         sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
  313         sc->et.et_quality = 1000;
  314         sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
  315         sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
  316         sc->et.et_start = a10_timer_timer_start;
  317         sc->et.et_stop = a10_timer_timer_stop;
  318         sc->et.et_priv = sc;
  319         et_register(&sc->et);
  320 }
  321 
  322 static int
  323 a10_timer_timer_start(struct eventtimer *et, sbintime_t first,
  324     sbintime_t period)
  325 {
  326         struct a10_timer_softc *sc;
  327         uint32_t count;
  328         uint32_t val;
  329 
  330         sc = (struct a10_timer_softc *)et->et_priv;
  331 
  332         if (period != 0)
  333                 sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
  334         else
  335                 sc->sc_period = 0;
  336         if (first != 0)
  337                 count = ((uint32_t)et->et_frequency * first) >> 32;
  338         else
  339                 count = sc->sc_period;
  340 
  341         /* Update timer values */
  342         timer_write_4(sc, TIMER_INTV_REG(0), sc->sc_period);
  343         timer_write_4(sc, TIMER_CURV_REG(0), count);
  344 
  345         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  346         if (period != 0) {
  347                 /* periodic */
  348                 val |= TIMER_CTRL_AUTORELOAD;
  349         } else {
  350                 /* oneshot */
  351                 val &= ~TIMER_CTRL_AUTORELOAD;
  352         }
  353         /* Enable timer0 */
  354         val |= TIMER_IRQ_ENABLE(0);
  355         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  356 
  357         return (0);
  358 }
  359 
  360 static int
  361 a10_timer_timer_stop(struct eventtimer *et)
  362 {
  363         struct a10_timer_softc *sc;
  364         uint32_t val;
  365 
  366         sc = (struct a10_timer_softc *)et->et_priv;
  367 
  368         /* Disable timer0 */
  369         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  370         val &= ~TIMER_CTRL_START;
  371         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  372 
  373         sc->sc_period = 0;
  374 
  375         return (0);
  376 }
  377 #endif
  378 
  379 /*
  380  * Timecounter functions for A23 and above
  381  */
  382 
  383 #if defined(__aarch64__)
  384 static void
  385 a23_timer_timecounter_setup(struct a10_timer_softc *sc)
  386 {
  387         uint32_t val;
  388 
  389         /* Set clock source to OSC24M, 1 pre-division, continuous mode */
  390         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  391         val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
  392         val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
  393         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  394 
  395         /* Set reload value */
  396         timer_write_4(sc, TIMER_INTV_REG(0), ~0);
  397         val = timer_read_4(sc, TIMER_INTV_REG(0));
  398 
  399         /* Enable timer0 */
  400         val = timer_read_4(sc, TIMER_CTRL_REG(0));
  401         val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
  402         timer_write_4(sc, TIMER_CTRL_REG(0), val);
  403 
  404         val = timer_read_4(sc, TIMER_CURV_REG(0));
  405 
  406         a23_timer_timecounter.tc_priv = sc;
  407         a23_timer_timecounter.tc_frequency = sc->timer0_freq;
  408         tc_init(&a23_timer_timecounter);
  409 }
  410 
  411 static u_int
  412 a23_timer_get_timecount(struct timecounter *tc)
  413 {
  414         struct a10_timer_softc *sc;
  415         uint32_t val;
  416 
  417         sc = (struct a10_timer_softc *)tc->tc_priv;
  418         if (sc == NULL)
  419                 return (0);
  420 
  421         val = timer_read_4(sc, TIMER_CURV_REG(0));
  422         /* Counter count backwards */
  423         return (~0u - val);
  424 }
  425 #endif
  426 
  427 /*
  428  * Timecounter functions for A10 and A13, using the 64 bits counter
  429  */
  430 
  431 static uint64_t
  432 timer_read_counter64(struct a10_timer_softc *sc)
  433 {
  434         uint32_t lo, hi;
  435 
  436         /* Latch counter, wait for it to be ready to read. */
  437         timer_write_4(sc, CNT64_CTRL_REG, CNT64_CTRL_RL_EN);
  438         while (timer_read_4(sc, CNT64_CTRL_REG) & CNT64_CTRL_RL_EN)
  439                 continue;
  440 
  441         hi = timer_read_4(sc, CNT64_HI_REG);
  442         lo = timer_read_4(sc, CNT64_LO_REG);
  443 
  444         return (((uint64_t)hi << 32) | lo);
  445 }
  446 
  447 #if defined(__arm__)
  448 static void
  449 a10_timer_delay(int usec, void *arg)
  450 {
  451         struct a10_timer_softc *sc = arg;
  452         uint64_t end, now;
  453 
  454         now = timer_read_counter64(sc);
  455         end = now + (sc->timer0_freq / 1000000) * (usec + 1);
  456 
  457         while (now < end)
  458                 now = timer_read_counter64(sc);
  459 }
  460 #endif
  461 
  462 static u_int
  463 a10_timer_get_timecount(struct timecounter *tc)
  464 {
  465 
  466         if (tc->tc_priv == NULL)
  467                 return (0);
  468 
  469         return ((u_int)timer_read_counter64(tc->tc_priv));
  470 }
  471 
  472 static device_method_t a10_timer_methods[] = {
  473         DEVMETHOD(device_probe,         a10_timer_probe),
  474         DEVMETHOD(device_attach,        a10_timer_attach),
  475 
  476         DEVMETHOD_END
  477 };
  478 
  479 static driver_t a10_timer_driver = {
  480         "a10_timer",
  481         a10_timer_methods,
  482         sizeof(struct a10_timer_softc),
  483 };
  484 
  485 static devclass_t a10_timer_devclass;
  486 
  487 EARLY_DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0,
  488     BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);

Cache object: 12da4261c62a5468e4779a36431fc8be


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