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.3/sys/arm/xscale/i80321/i80321_timer.c 172731 2007-10-17 23:29:02Z 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 #include "opt_timer.h"
   65 
   66 void (*i80321_hardclock_hook)(void) = NULL;
   67 struct i80321_timer_softc {
   68         device_t        dev;
   69 } timer_softc;
   70 
   71 
   72 static unsigned i80321_timer_get_timecount(struct timecounter *tc);
   73         
   74 
   75 static uint32_t counts_per_hz;
   76 
   77 static uint32_t offset = 0;
   78 static int32_t last = -1;
   79 static int ticked = 0;
   80 
   81 #ifndef COUNTS_PER_SEC
   82 #define COUNTS_PER_SEC          200000000       /* 200MHz */
   83 #endif
   84 #define COUNTS_PER_USEC         (COUNTS_PER_SEC / 1000000)
   85 
   86 static struct timecounter i80321_timer_timecounter = {
   87         i80321_timer_get_timecount, /* get_timecount */
   88         NULL,                       /* no poll_pps */
   89         ~0u,                        /* counter_mask */
   90         COUNTS_PER_SEC,            /* frequency */
   91         "i80321 timer",             /* name */
   92         1000                        /* quality */
   93 };
   94 
   95 static int
   96 i80321_timer_probe(device_t dev)
   97 {
   98 
   99         device_set_desc(dev, "i80321 timer");
  100         return (0);
  101 }
  102 
  103 static int
  104 i80321_timer_attach(device_t dev)
  105 {
  106         timer_softc.dev = dev;
  107 
  108         return (0);
  109 }
  110 
  111 static device_method_t i80321_timer_methods[] = {
  112         DEVMETHOD(device_probe, i80321_timer_probe),
  113         DEVMETHOD(device_attach, i80321_timer_attach),
  114         {0, 0},
  115 };
  116 
  117 static driver_t i80321_timer_driver = {
  118         "itimer",
  119         i80321_timer_methods,
  120         sizeof(struct i80321_timer_softc),
  121 };
  122 static devclass_t i80321_timer_devclass;
  123 
  124 DRIVER_MODULE(itimer, iq, i80321_timer_driver, i80321_timer_devclass, 0, 0);
  125 
  126 void    counterhandler(void *);
  127 void    clockhandler(void *);
  128 
  129 
  130 static __inline uint32_t
  131 tmr1_read(void)
  132 {
  133         uint32_t rv;
  134 
  135         __asm __volatile("mrc p6, 0, %0, c1, c1, 0"
  136                 : "=r" (rv));
  137         return (rv);
  138 }
  139 
  140 static __inline void
  141 tmr1_write(uint32_t val)
  142 {
  143 
  144         __asm __volatile("mcr p6, 0, %0, c1, c1, 0"
  145                 :
  146                 : "r" (val));
  147 }
  148 
  149 static __inline uint32_t
  150 tcr1_read(void)
  151 {
  152         uint32_t rv;
  153 
  154         __asm __volatile("mrc p6, 0, %0, c3, c1, 0"
  155                 : "=r" (rv));
  156         return (rv);
  157 }
  158 static __inline void
  159 tcr1_write(uint32_t val)
  160 {
  161 
  162         __asm __volatile("mcr p6, 0, %0, c3, c1, 0"
  163                 :
  164                 : "r" (val));
  165 }
  166 
  167 static __inline void
  168 trr1_write(uint32_t val)
  169 {
  170 
  171         __asm __volatile("mcr p6, 1, %0, c5, c1, 0"
  172                 :
  173                 : "r" (val));
  174 }
  175 
  176 static __inline uint32_t
  177 tmr0_read(void)
  178 {
  179         uint32_t rv;
  180 
  181         __asm __volatile("mrc p6, 0, %0, c0, c1, 0"
  182                 : "=r" (rv));
  183         return (rv);
  184 }
  185 
  186 static __inline void
  187 tmr0_write(uint32_t val)
  188 {
  189 
  190         __asm __volatile("mcr p6, 0, %0, c0, c1, 0"
  191                 :
  192                 : "r" (val));
  193 }
  194 
  195 static __inline uint32_t
  196 tcr0_read(void)
  197 {
  198         uint32_t rv;
  199 
  200         __asm __volatile("mrc p6, 0, %0, c2, c1, 0"
  201                 : "=r" (rv));
  202         return (rv);
  203 }
  204 static __inline void
  205 tcr0_write(uint32_t val)
  206 {
  207 
  208         __asm __volatile("mcr p6, 0, %0, c2, c1, 0"
  209                 :
  210                 : "r" (val));
  211 }
  212 
  213 static __inline void
  214 trr0_write(uint32_t val)
  215 {
  216 
  217         __asm __volatile("mcr p6, 0, %0, c4, c1, 0"
  218                 :
  219                 : "r" (val));
  220 }
  221 
  222 static __inline void
  223 tisr_write(uint32_t val)
  224 {
  225 
  226         __asm __volatile("mcr p6, 0, %0, c6, c1, 0"
  227                 :
  228                 : "r" (val));
  229 }
  230 
  231 static __inline uint32_t
  232 tisr_read(void)
  233 {
  234         int ret;
  235         
  236         __asm __volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (ret));
  237         return (ret);
  238 }
  239 
  240 static unsigned
  241 i80321_timer_get_timecount(struct timecounter *tc)
  242 {
  243         int32_t cur = tcr0_read();
  244         
  245         if (cur > last && last != -1) {
  246                 offset += counts_per_hz;
  247                 if (ticked > 0)
  248                                                                                                 ticked--;
  249         }
  250         if (ticked) {
  251                 offset += ticked * counts_per_hz;
  252                 ticked = 0;
  253         }
  254         last = cur;
  255         return (counts_per_hz - cur + offset);
  256 }
  257 /*
  258  * i80321_calibrate_delay:
  259  *
  260  *      Calibrate the delay loop.
  261  */
  262 void
  263 i80321_calibrate_delay(void)
  264 {
  265 
  266         /*
  267          * Just use hz=100 for now -- we'll adjust it, if necessary,
  268          * in cpu_initclocks().
  269          */
  270         counts_per_hz = COUNTS_PER_SEC / 100;
  271 
  272         tmr0_write(0);                  /* stop timer */
  273         tisr_write(TISR_TMR0);          /* clear interrupt */
  274         trr0_write(counts_per_hz);      /* reload value */
  275         tcr0_write(counts_per_hz);      /* current value */
  276 
  277         tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
  278 }
  279 
  280 /*
  281  * cpu_initclocks:
  282  *
  283  *      Initialize the clock and get them going.
  284  */
  285 void
  286 cpu_initclocks(void)
  287 {
  288         u_int oldirqstate;
  289         struct resource *irq;
  290         int rid = 0;
  291         void *ihl;
  292         device_t dev = timer_softc.dev;
  293 
  294         if (hz < 50 || COUNTS_PER_SEC % hz) {
  295                 printf("Cannot get %d Hz clock; using 100 Hz\n", hz);
  296                 hz = 100;
  297         }
  298         tick = 1000000 / hz;    /* number of microseconds between interrupts */
  299 
  300         /*
  301          * We only have one timer available; stathz and profhz are
  302          * always left as 0 (the upper-layer clock code deals with
  303          * this situation).
  304          */
  305         if (stathz != 0)
  306                 printf("Cannot get %d Hz statclock\n", stathz);
  307         stathz = 0;
  308 
  309         if (profhz != 0)
  310                 printf("Cannot get %d Hz profclock\n", profhz);
  311         profhz = 0;
  312 
  313         /* Report the clock frequency. */
  314 
  315         oldirqstate = disable_interrupts(I32_bit);
  316 
  317         irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ICU_INT_TMR0,
  318             ICU_INT_TMR0, 1, RF_ACTIVE);
  319         if (!irq)
  320                 panic("Unable to setup the clock irq handler.\n");
  321         else
  322                 bus_setup_intr(dev, irq, INTR_TYPE_CLK | INTR_FAST, 
  323                     clockhandler, NULL, &ihl);
  324         tmr0_write(0);                  /* stop timer */
  325         tisr_write(TISR_TMR0);          /* clear interrupt */
  326 
  327         counts_per_hz = COUNTS_PER_SEC / hz;
  328 
  329         trr0_write(counts_per_hz);      /* reload value */
  330         tcr0_write(counts_per_hz);      /* current value */
  331         tmr0_write(TMRx_ENABLE|TMRx_RELOAD|TMRx_CSEL_CORE);
  332 
  333         tc_init(&i80321_timer_timecounter);
  334         restore_interrupts(oldirqstate);
  335 }
  336 
  337 
  338 /*
  339  * DELAY:
  340  *
  341  *      Delay for at least N microseconds.
  342  */
  343 void
  344 DELAY(int n)
  345 {
  346         uint32_t cur, last, delta, usecs;
  347 
  348         /*
  349          * This works by polling the timer and counting the
  350          * number of microseconds that go by.
  351          */
  352         last = tcr0_read();
  353         delta = usecs = 0;
  354 
  355         while (n > usecs) {
  356                 cur = tcr0_read();
  357 
  358                 /* Check to see if the timer has wrapped around. */
  359                 if (last < cur)
  360                         delta += (last + (counts_per_hz - cur));
  361                 else
  362                         delta += (last - cur);
  363 
  364                 last = cur;
  365 
  366                 if (delta >= COUNTS_PER_USEC) {
  367                         usecs += delta / COUNTS_PER_USEC;
  368                         delta %= COUNTS_PER_USEC;
  369                 }
  370         }
  371 }
  372 
  373 /*
  374  * clockhandler:
  375  *
  376  *      Handle the hardclock interrupt.
  377  */
  378 void
  379 clockhandler(void *arg)
  380 {
  381         struct clockframe *frame = arg;
  382 
  383         ticked++;
  384         tisr_write(TISR_TMR0);
  385         hardclock(frame);
  386 
  387         if (i80321_hardclock_hook != NULL)
  388                 (*i80321_hardclock_hook)();
  389         return;
  390 }
  391 
  392 void
  393 cpu_startprofclock(void)
  394 {
  395 }
  396 
  397 void
  398 cpu_stopprofclock(void)
  399 {
  400         
  401 }

Cache object: c6f4254605f6301610b95a2a47f5a88d


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