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/xscale/i80321/i80321_timer.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: i80321_timer.c,v 1.7 2003/07/27 04:52:28 thorpej Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
    5  * All rights reserved.
    6  *
    7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed for the NetBSD Project by
   20  *      Wasabi Systems, Inc.
   21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   22  *    or promote products derived from this software without specific prior
   23  *    written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35  * POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 
   38 /*
   39  * Timer/clock support for the Intel i80321 I/O processor.
   40  */
   41 
   42 #include <sys/cdefs.h>
   43 __FBSDID("$FreeBSD: releng/6.0/sys/arm/xscale/i80321/i80321_timer.c 141817 2005-02-13 18:05:36Z cognet $");
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/kernel.h>
   48 #include <sys/module.h>
   49 #include <sys/time.h>
   50 #include <sys/bus.h>
   51 #include <sys/resource.h>
   52 #include <sys/rman.h>
   53 #include <sys/timetc.h>
   54 
   55 #include <machine/bus.h>
   56 #include <machine/cpufunc.h>
   57 #include <machine/resource.h>
   58 #include <machine/intr.h>
   59 #include <arm/xscale/i80321/i80321reg.h>
   60 #include <arm/xscale/i80321/i80321var.h>
   61 
   62 #include <arm/xscale/xscalevar.h>
   63 
   64 void (*i80321_hardclock_hook)(void) = NULL;
   65 struct i80321_timer_softc {
   66         device_t        dev;
   67 } timer_softc;
   68 
   69 
   70 static unsigned i80321_timer_get_timecount(struct timecounter *tc);
   71         
   72 
   73 static uint32_t counts_per_hz;
   74 
   75 static uint32_t offset = 0;
   76 static int32_t last = -1;
   77 static int ticked = 0;
   78 
   79 #define COUNTS_PER_SEC          200000000       /* 200MHz */
   80 #define COUNTS_PER_USEC         (COUNTS_PER_SEC / 1000000)
   81 
   82 static struct timecounter i80321_timer_timecounter = {
   83         i80321_timer_get_timecount, /* get_timecount */
   84         NULL,                       /* no poll_pps */
   85         ~0u,                        /* counter_mask */
   86         COUNTS_PER_SEC,            /* frequency */
   87         "i80321 timer",             /* name */
   88         1000                        /* quality */
   89 };
   90 
   91 static int
   92 i80321_timer_probe(device_t dev)
   93 {
   94 
   95         device_set_desc(dev, "i80321 timer");
   96         return (0);
   97 }
   98 
   99 static int
  100 i80321_timer_attach(device_t dev)
  101 {
  102         timer_softc.dev = dev;
  103 
  104         return (0);
  105 }
  106 
  107 static device_method_t i80321_timer_methods[] = {
  108         DEVMETHOD(device_probe, i80321_timer_probe),
  109         DEVMETHOD(device_attach, i80321_timer_attach),
  110         {0, 0},
  111 };
  112 
  113 static driver_t i80321_timer_driver = {
  114         "itimer",
  115         i80321_timer_methods,
  116         sizeof(struct i80321_timer_softc),
  117 };
  118 static devclass_t i80321_timer_devclass;
  119 
  120 DRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0);
  121 
  122 void    counterhandler(void *);
  123 void    clockhandler(void *);
  124 
  125 
  126 static __inline uint32_t
  127 tmr1_read(void)
  128 {
  129         uint32_t rv;
  130 
  131         __asm __volatile("mrc p6, 0, %0, c1, c1, 0"
  132                 : "=r" (rv));
  133         return (rv);
  134 }
  135 
  136 static __inline void
  137 tmr1_write(uint32_t val)
  138 {
  139 
  140         __asm __volatile("mcr p6, 0, %0, c1, c1, 0"
  141                 :
  142                 : "r" (val));
  143 }
  144 
  145 static __inline uint32_t
  146 tcr1_read(void)
  147 {
  148         uint32_t rv;
  149 
  150         __asm __volatile("mrc p6, 0, %0, c3, c1, 0"
  151                 : "=r" (rv));
  152         return (rv);
  153 }
  154 static __inline void
  155 tcr1_write(uint32_t val)
  156 {
  157 
  158         __asm __volatile("mcr p6, 0, %0, c3, c1, 0"
  159                 :
  160                 : "r" (val));
  161 }
  162 
  163 static __inline void
  164 trr1_write(uint32_t val)
  165 {
  166 
  167         __asm __volatile("mcr p6, 1, %0, c5, c1, 0"
  168                 :
  169                 : "r" (val));
  170 }
  171 
  172 static __inline uint32_t
  173 tmr0_read(void)
  174 {
  175         uint32_t rv;
  176 
  177         __asm __volatile("mrc p6, 0, %0, c0, c1, 0"
  178                 : "=r" (rv));
  179         return (rv);
  180 }
  181 
  182 static __inline void
  183 tmr0_write(uint32_t val)
  184 {
  185 
  186         __asm __volatile("mcr p6, 0, %0, c0, c1, 0"
  187                 :
  188                 : "r" (val));
  189 }
  190 
  191 static __inline uint32_t
  192 tcr0_read(void)
  193 {
  194         uint32_t rv;
  195 
  196         __asm __volatile("mrc p6, 0, %0, c2, c1, 0"
  197                 : "=r" (rv));
  198         return (rv);
  199 }
  200 static __inline void
  201 tcr0_write(uint32_t val)
  202 {
  203 
  204         __asm __volatile("mcr p6, 0, %0, c2, c1, 0"
  205                 :
  206                 : "r" (val));
  207 }
  208 
  209 static __inline void
  210 trr0_write(uint32_t val)
  211 {
  212 
  213         __asm __volatile("mcr p6, 0, %0, c4, c1, 0"
  214                 :
  215                 : "r" (val));
  216 }
  217 
  218 static __inline void
  219 tisr_write(uint32_t val)
  220 {
  221 
  222         __asm __volatile("mcr p6, 0, %0, c6, c1, 0"
  223                 :
  224                 : "r" (val));
  225 }
  226 
  227 static __inline uint32_t
  228 tisr_read(void)
  229 {
  230         int ret;
  231         
  232         __asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
  233         return (ret);
  234 }
  235 
  236 static unsigned
  237 i80321_timer_get_timecount(struct timecounter *tc)
  238 {
  239         int32_t cur = tcr0_read();
  240         
  241         if (cur > last && last != -1) {
  242                 offset += counts_per_hz;
  243                 if (ticked > 0)
  244                                                                                                 ticked--;
  245         }
  246         if (ticked) {
  247                 offset += ticked * counts_per_hz;
  248                 ticked = 0;
  249         }
  250         last = cur;
  251         return (counts_per_hz - cur + offset);
  252 }
  253 /*
  254  * i80321_calibrate_delay:
  255  *
  256  *      Calibrate the delay loop.
  257  */
  258 void
  259 i80321_calibrate_delay(void)
  260 {
  261 
  262         /*
  263          * Just use hz=100 for now -- we'll adjust it, if necessary,
  264          * in cpu_initclocks().
  265          */
  266         counts_per_hz = COUNTS_PER_SEC / 100;
  267 
  268         tmr0_write(0);                  /* stop timer */
  269         tisr_write(TISR_TMR0);          /* clear interrupt */
  270         trr0_write(counts_per_hz);      /* reload value */
  271         tcr0_write(counts_per_hz);      /* current value */
  272 
  273         tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
  274 }
  275 
  276 /*
  277  * cpu_initclocks:
  278  *
  279  *      Initialize the clock and get them going.
  280  */
  281 void
  282 cpu_initclocks(void)
  283 {
  284         u_int oldirqstate;
  285         struct resource *irq;
  286         int rid = 0;
  287         void *ihl;
  288         device_t dev = timer_softc.dev;
  289 
  290         if (hz < 50 || COUNTS_PER_SEC % hz) {
  291                 printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
  292                 hz = 100;
  293         }
  294         tick = 1000000 / hz;    /* number of microseconds between interrupts */
  295 
  296         /*
  297          * We only have one timer available; stathz and profhz are
  298          * always left as 0 (the upper-layer clock code deals with
  299          * this situation).
  300          */
  301         if (stathz != 0)
  302                 printf("Cannot get %d Hz statclock\n", stathz);
  303         stathz = 0;
  304 
  305         if (profhz != 0)
  306                 printf("Cannot get %d Hz profclock\n", profhz);
  307         profhz = 0;
  308 
  309         /* Report the clock frequency. */
  310 
  311         oldirqstate = disable_interrupts(I32_bit);
  312 
  313         irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ICU_INT_TMR0,
  314             ICU_INT_TMR0, 1, RF_ACTIVE);
  315         if (!irq)
  316                 panic("Unable to setup the clock irq handler.\n");
  317         else
  318                 bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST, 
  319                     clockhandler, NULL, &ihl);
  320         tmr0_write(0);                  /* stop timer */
  321         tisr_write(TISR_TMR0);          /* clear interrupt */
  322 
  323         counts_per_hz = COUNTS_PER_SEC / hz;
  324 
  325         trr0_write(counts_per_hz);      /* reload value */
  326         tcr0_write(counts_per_hz);      /* current value */
  327         tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
  328 
  329         tc_init(&i80321_timer_timecounter);
  330         restore_interrupts(oldirqstate);
  331 }
  332 
  333 
  334 /*
  335  * DELAY:
  336  *
  337  *      Delay for at least N microseconds.
  338  */
  339 void
  340 DELAY(int n)
  341 {
  342         uint32_t cur, last, delta, usecs;
  343 
  344         /*
  345          * This works by polling the timer and counting the
  346          * number of microseconds that go by.
  347          */
  348         last = tcr0_read();
  349         delta = usecs = 0;
  350 
  351         while (n > usecs) {
  352                 cur = tcr0_read();
  353 
  354                 /* Check to see if the timer has wrapped around. */
  355                 if (last < cur)
  356                         delta += (last + (counts_per_hz - cur));
  357                 else
  358                         delta += (last - cur);
  359 
  360                 last = cur;
  361 
  362                 if (delta >= COUNTS_PER_USEC) {
  363                         usecs += delta / COUNTS_PER_USEC;
  364                         delta %= COUNTS_PER_USEC;
  365                 }
  366         }
  367 }
  368 
  369 /*
  370  * clockhandler:
  371  *
  372  *      Handle the hardclock interrupt.
  373  */
  374 void
  375 clockhandler(void *arg)
  376 {
  377         struct clockframe *frame = arg;
  378 
  379         ticked++;
  380         tisr_write(TISR_TMR0);
  381         hardclock(frame);
  382 
  383         if (i80321_hardclock_hook != NULL)
  384                 (*i80321_hardclock_hook)();
  385         return;
  386 }
  387 
  388 void
  389 cpu_startprofclock(void)
  390 {
  391 }
  392 
  393 void
  394 cpu_stopprofclock(void)
  395 {
  396         
  397 }

Cache object: 64b58f205505749767f7f47d383a4fcc


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