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/bitsy/clock.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 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "io.h"
    7 #include        "ureg.h"
    8 #include        "../port/error.h"
    9 
   10 
   11 enum {
   12         RTCREGS =       0x90010000,     /* real time clock registers */
   13         RTSR_al =       0x01,           /* alarm detected */
   14         RTSR_hz =       0x02,           /* 1Hz tick */
   15         RTSR_ale=       0x04,           /* alarm interrupt enable */
   16         RTSR_hze=       0x08,           /* 1Hz tick enable */
   17 
   18         Never   =       0xffffffff,
   19 };
   20 
   21 typedef struct OSTimer
   22 {
   23         ulong           osmr[4];        /* match registers */
   24         volatile ulong  oscr;           /* counter register */
   25         ulong           ossr;           /* status register */
   26         ulong           ower;   /* watchdog enable register */
   27         ulong           oier;           /* timer interrupt enable register */
   28 } OSTimer;
   29 
   30 typedef struct RTCregs 
   31 {
   32         ulong   rtar;   /* alarm */
   33         ulong   rcnr;   /* count */
   34         ulong   rttr;   /* trim */
   35         ulong   dummy;  /* hole */
   36         ulong   rtsr;   /* status */
   37 } RTCregs;
   38 
   39 OSTimer *timerregs = (OSTimer*)OSTIMERREGS;
   40 RTCregs *rtcregs = (RTCregs*)RTCREGS;
   41 static int clockinited;
   42 
   43 static void     clockintr(Ureg*, void*);
   44 static void     rtcintr(Ureg*, void*);
   45 static Tval     when;   /* scheduled time of next interrupt */
   46 
   47 long    timeradjust;
   48 
   49 enum
   50 {
   51         Minfreq = ClockFreq/HZ,         /* At least one interrupt per HZ (50 ms) */
   52         Maxfreq = ClockFreq/10000,      /* At most one interrupt every 100 µs */
   53 };
   54 
   55 ulong
   56 clockpower(int on)
   57 {
   58         static ulong savedtime;
   59 
   60         if (on){
   61                 timerregs->ossr |= 1<<0;
   62                 timerregs->oier = 1<<0;
   63                 timerregs->osmr[0] = timerregs->oscr + Minfreq;
   64                 if (rtcregs->rttr == 0){
   65                         rtcregs->rttr = 0x8000; // nominal frequency.
   66                         rtcregs->rcnr = 0;
   67                         rtcregs->rtar = 0xffffffff;
   68                         rtcregs->rtsr |= RTSR_ale;
   69                         rtcregs->rtsr |= RTSR_hze;
   70                 }
   71                 if (rtcregs->rcnr > savedtime)
   72                         return rtcregs->rcnr - savedtime;
   73         } else
   74                 savedtime = rtcregs->rcnr;
   75         clockinited = on;
   76         return 0L;
   77 }
   78 
   79 void
   80 clockinit(void)
   81 {
   82         ulong x;
   83         ulong id;
   84 
   85         /* map the clock registers */
   86         timerregs = mapspecial(OSTIMERREGS, sizeof(OSTimer));
   87         rtcregs   = mapspecial(RTCREGS, sizeof(RTCregs));
   88 
   89         /* enable interrupts on match register 0, turn off all others */
   90         timerregs->ossr |= 1<<0;
   91         intrenable(IRQ, IRQtimer0, clockintr, nil, "clock");
   92         timerregs->oier = 1<<0;
   93 
   94         /* figure out processor frequency */
   95         x = powerregs->ppcr & 0x1f;
   96         conf.hz = ClockFreq*(x*4+16);
   97         conf.mhz = (conf.hz+499999)/1000000;
   98 
   99         /* get processor type */
  100         id = getcpuid();
  101 
  102         print("%lud MHZ ARM, ver %lux/part %lux/step %lud\n", conf.mhz,
  103                 (id>>16)&0xff, (id>>4)&0xfff, id&0xf);
  104 
  105         /* post interrupt 1/HZ secs from now */
  106         when = timerregs->oscr + Minfreq;
  107         timerregs->osmr[0] = when;
  108 
  109         /* enable RTC interrupts and alarms */
  110         intrenable(IRQ, IRQrtc, rtcintr, nil, "rtc");
  111         rtcregs->rttr = 0x8000;         // make rcnr   1Hz
  112         rtcregs->rcnr = 0;              // reset counter
  113         rtcregs->rtsr |= RTSR_al;
  114         rtcregs->rtsr |= RTSR_ale;
  115 
  116         timersinit();
  117 
  118         clockinited = 1;
  119 }
  120 
  121 /*  turn 32 bit counter into a 64 bit one.  since todfix calls
  122  *  us at least once a second and we overflow once every 1165
  123  *  seconds, we won't miss an overflow.
  124  */
  125 uvlong
  126 fastticks(uvlong *hz)
  127 {
  128         static uvlong high;
  129         static ulong last;
  130         ulong x;
  131 
  132         if(hz != nil)
  133                 *hz = ClockFreq;
  134         x = timerregs->oscr;
  135         if(x < last)
  136                 high += 1LL<<32;
  137         last = x;
  138         return high+x;
  139 }
  140 
  141 ulong
  142 µs(void)
  143 {
  144         return fastticks2us(fastticks(nil));
  145 }
  146 
  147 void
  148 timerset(Tval v)
  149 {
  150         ulong next, tics;       /* Must be unsigned! */
  151         static int count;
  152 
  153         next = v;
  154 
  155         /* post next interrupt: calculate # of tics from now */
  156         tics = next - timerregs->oscr - Maxfreq;
  157         if (tics > Minfreq){
  158                 timeradjust++;
  159                 next = timerregs->oscr + Maxfreq;
  160         }
  161         timerregs->osmr[0] = next;
  162 }
  163 
  164 static void
  165 clockintr(Ureg *ureg, void*)
  166 {
  167         /* reset previous interrupt */
  168         timerregs->ossr |= 1<<0;
  169         when += Minfreq;
  170         timerregs->osmr[0] = when;      /* insurance */
  171 
  172         timerintr(ureg, when);
  173 }
  174 
  175 void
  176 rtcalarm(ulong secs)
  177 {
  178         vlong t;
  179 
  180         if (t == 0){
  181                 iprint("RTC alarm cancelled\n");
  182                 rtcregs->rtsr &= ~RTSR_ale;
  183                 rtcregs->rtar = 0xffffffff;
  184         } else {
  185                 t = todget(nil);
  186                 t = t / 1000000000ULL; // nsec to secs
  187                 if (secs < t)
  188                         return;
  189                 secs -= t;
  190                 iprint("RTC alarm set to %uld seconds from now\n", secs);
  191                 rtcregs->rtar = rtcregs->rcnr + secs;
  192                 rtcregs->rtsr|= RTSR_ale;
  193         }
  194 }
  195 
  196 static void
  197 rtcintr(Ureg*, void*)
  198 {
  199         /* reset interrupt */
  200         rtcregs->rtsr&= ~RTSR_ale;
  201         rtcregs->rtsr&= ~RTSR_al;
  202 
  203         rtcregs->rtar = 0;
  204         iprint("RTC alarm: %lud\n", rtcregs->rcnr);
  205 }
  206 
  207 void
  208 delay(int ms)
  209 {
  210         ulong start;
  211         int i;
  212 
  213         if(clockinited){
  214                 while(ms-- > 0){
  215                         start = timerregs->oscr;
  216                         while(timerregs->oscr-start < ClockFreq/1000)
  217                                 ;
  218                 }
  219         } else {
  220                 while(ms-- > 0){
  221                         for(i = 0; i < 1000; i++)
  222                                 ;
  223                 }
  224         }
  225 }
  226 
  227 void
  228 microdelay(int µs)
  229 {
  230         ulong start;
  231         int i;
  232 
  233         µs++;
  234         if(clockinited){
  235                 start = timerregs->oscr;
  236                 while(timerregs->oscr - start < 1UL+(µs*ClockFreq)/1000000UL)
  237                         ;
  238         } else {
  239                 while(µs-- > 0){
  240                         for(i = 0; i < 10; i++)
  241                                 ;
  242                 }
  243         }
  244 }
  245 
  246 /*  
  247  *  performance measurement ticks.  must be low overhead.
  248  *  doesn't have to count over a second.
  249  */
  250 ulong
  251 perfticks(void)
  252 {
  253         return timerregs->oscr;
  254 }

Cache object: 9e5ecc7ed675c381e947f0b4f696b916


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