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

Cache object: 6f914bde5cdafb258940a159c97239a8


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