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

Cache object: bab6e469cca997c2120c3eb885f895e2


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