time.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/mips/philips/nino/time.c
  3.  *
  4.  *  Copyright (C) 1999 Harald Koerfgen
  5.  *  Copyright (C) 2000 Pavel Machek (pavel@suse.cz)
  6.  *  Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com)
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License version 2 as
  10.  * published by the Free Software Foundation.
  11.  *
  12.  *  Time handling functinos for Philips Nino.
  13.  */
  14. #include <linux/errno.h>
  15. #include <linux/init.h>
  16. #include <linux/sched.h>
  17. #include <linux/kernel.h>
  18. #include <linux/param.h>
  19. #include <linux/string.h>
  20. #include <linux/mm.h>
  21. #include <linux/interrupt.h>
  22. #include <linux/timex.h>
  23. #include <linux/delay.h>
  24. #include <asm/tx3912.h>
  25. extern volatile unsigned long wall_jiffies;
  26. extern rwlock_t xtime_lock;
  27. static struct timeval xbase;
  28. #define USECS_PER_JIFFY (1000000/HZ)
  29. /*
  30.  * Poll the Interrupt Status Registers
  31.  */
  32. #undef POLL_STATUS
  33. static unsigned long do_gettimeoffset(void)
  34. {
  35.     /*
  36.      * This is a kludge
  37.      */
  38.     return 0;
  39. }
  40. static
  41. void inline readRTC(unsigned long *high, unsigned long *low)
  42. {
  43. /* read twice, and keep reading till we find two
  44.  * the same pairs. This is needed in case the RTC
  45.  * was updating its registers and we read a old
  46.  * High but a new Low. */
  47. do {
  48. *high = RTChigh & RTC_HIGHMASK;
  49. *low = RTClow;
  50. } while (*high != (RTChigh & RTC_HIGHMASK) || RTClow!=*low);
  51. }
  52. /*
  53.  * This version of gettimeofday has near millisecond resolution.
  54.  */
  55. void do_gettimeofday(struct timeval *tv)
  56. {
  57.     unsigned long flags;
  58.     unsigned long high, low;
  59.     read_lock_irqsave(&xtime_lock, flags);
  60.     // 40 bit RTC, driven by 32khz source:
  61.     // +-----------+-----------------------------------------+
  62.     // | HHHH.HHHH | LLLL.LLLL.LLLL.LLLL.LMMM.MMMM.MMMM.MMMM |
  63.     // +-----------+-----------------------------------------+
  64.     readRTC(&high,&low);
  65.     tv->tv_sec  = (high << 17) | (low >> 15);
  66.     tv->tv_usec = (low % 32768) * 1953 / 64;
  67.     tv->tv_sec += xbase.tv_sec;
  68.     tv->tv_usec += xbase.tv_usec;
  69.     tv->tv_usec += do_gettimeoffset();
  70.     /*
  71.      * xtime is atomically updated in timer_bh. lost_ticks is
  72.      * nonzero if the timer bottom half hasnt executed yet.
  73.      */
  74.     if (jiffies - wall_jiffies)
  75. tv->tv_usec += USECS_PER_JIFFY;
  76.     read_unlock_irqrestore(&xtime_lock, flags);
  77.     if (tv->tv_usec >= 1000000) {
  78. tv->tv_usec -= 1000000;
  79. tv->tv_sec++;
  80.     }
  81. }
  82. void do_settimeofday(struct timeval *tv)
  83. {
  84.     write_lock_irq(&xtime_lock);
  85.     /* This is revolting. We need to set the xtime.tv_usec
  86.      * correctly. However, the value in this location is
  87.      * is value at the last tick.
  88.      * Discover what correction gettimeofday
  89.      * would have done, and then undo it!
  90.      */
  91.     tv->tv_usec -= do_gettimeoffset();
  92.     if (tv->tv_usec < 0) {
  93. tv->tv_usec += 1000000;
  94. tv->tv_sec--;
  95.     }
  96.     /* reset RTC to 0 (real time is xbase + RTC) */
  97.     xbase = *tv;
  98.     RTCtimerControl |=  TIM_RTCCLEAR;
  99.     RTCtimerControl &= ~TIM_RTCCLEAR;
  100.     RTCalarmHigh = RTCalarmLow = ~0UL;
  101.     xtime = *tv;
  102.     time_state = TIME_BAD;
  103.     time_maxerror = MAXPHASE;
  104.     time_esterror = MAXPHASE;
  105.     write_unlock_irq(&xtime_lock);
  106. }
  107. static int set_rtc_mmss(unsigned long nowtime)
  108. {
  109.     int retval = 0;
  110.     return retval;
  111. }
  112. /* last time the cmos clock got updated */
  113. static long last_rtc_update = 0;
  114. /*
  115.  * timer_interrupt() needs to keep up the real-time clock,
  116.  * as well as call the "do_timer()" routine every clocktick
  117.  */
  118. int do_write = 1;
  119. static void
  120. timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  121. {
  122. #ifdef POLL_STATUS
  123.     static unsigned long old_IntStatus1 = 0;
  124.     static unsigned long old_IntStatus3 = 0;
  125.     static unsigned long old_IntStatus4 = 0;
  126.     static unsigned long old_IntStatus5 = 0;
  127.     static int counter = 0;
  128.     int i;
  129.     new_spircv = SPIData & 0xff;
  130.     if ((old_spircv != new_spircv) && (new_spircv != 0xff)) {
  131.     printk( "SPIData changed: %xn", new_spircv );
  132.     }
  133.     old_spircv = new_spircv;
  134.     if (do_write)
  135.     SPIData = 0;
  136. #endif
  137.     if (!user_mode(regs)) {
  138. if (prof_buffer && current->pid) {
  139.     extern int _stext;
  140.     unsigned long pc = regs->cp0_epc;
  141.     pc -= (unsigned long) &_stext;
  142.     pc >>= prof_shift;
  143.     /*
  144.      * Dont ignore out-of-bounds pc values silently,
  145.      * put them into the last histogram slot, so if
  146.      * present, they will show up as a sharp peak.
  147.      */
  148.     if (pc > prof_len - 1)
  149. pc = prof_len - 1;
  150. atomic_inc((atomic_t *) & prof_buffer[pc]);
  151.     }
  152.     }
  153.     /*
  154.      * aaaand... action!
  155.      */
  156.     do_timer(regs);
  157.     /*
  158.      * If we have an externally syncronized Linux clock, then update
  159.      * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
  160.      * called as close as possible to 500 ms before the new second starts.
  161.      */
  162.     if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
  163. xtime.tv_usec > 500000 - (tick >> 1) &&
  164. xtime.tv_usec < 500000 + (tick >> 1))
  165.     {
  166. if (set_rtc_mmss(xtime.tv_sec) == 0)
  167.     last_rtc_update = xtime.tv_sec;
  168. else
  169.     last_rtc_update = xtime.tv_sec - 600;  /* do it again in 60 s */
  170.     }
  171. }
  172. static struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
  173.    "timer", NULL, NULL};
  174. void (*board_time_init) (struct irqaction * irq);
  175. int __init time_init(void)
  176. {
  177.     struct timeval starttime;
  178.     starttime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
  179.     starttime.tv_usec = 0;
  180.     do_settimeofday(&starttime);
  181.     board_time_init(&irq0);
  182.     return 0;
  183. }