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

Cache object: cfd65600ae33a522f63e487b50e9c5c6


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