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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 2001 MontaVista Software, ppopov@mvista.com
  3.  * Copied and modified Carsten Langgaard's time.c
  4.  *
  5.  * Carsten Langgaard, carstenl@mips.com
  6.  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
  7.  *
  8.  * ########################################################################
  9.  *
  10.  *  This program is free software; you can distribute it and/or modify it
  11.  *  under the terms of the GNU General Public License (Version 2) as
  12.  *  published by the Free Software Foundation.
  13.  *
  14.  *  This program is distributed in the hope it will be useful, but WITHOUT
  15.  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16.  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17.  *  for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public License along
  20.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  21.  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  22.  *
  23.  * ########################################################################
  24.  *
  25.  * Setting up the clock on the MIPS boards.
  26.  */
  27. #include <linux/config.h>
  28. #include <linux/init.h>
  29. #include <linux/kernel_stat.h>
  30. #include <linux/sched.h>
  31. #include <linux/spinlock.h>
  32. #include <asm/mipsregs.h>
  33. #include <asm/ptrace.h>
  34. #include <asm/div64.h>
  35. #include <asm/au1000.h>
  36. #include <linux/mc146818rtc.h>
  37. #include <linux/timex.h>
  38. extern volatile unsigned long wall_jiffies;
  39. unsigned long missed_heart_beats = 0;
  40. unsigned long uart_baud_base;
  41. static unsigned long r4k_offset; /* Amount to increment compare reg each time */
  42. static unsigned long r4k_cur;    /* What counter should be at next timer irq */
  43. extern rwlock_t xtime_lock;
  44. #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
  45. static inline void ack_r4ktimer(unsigned long newval)
  46. {
  47. write_32bit_cp0_register(CP0_COMPARE, newval);
  48. }
  49. /*
  50.  * There are a lot of conceptually broken versions of the MIPS timer interrupt
  51.  * handler floating around.  This one is rather different, but the algorithm
  52.  * is provably more robust.
  53.  */
  54. unsigned long wtimer;
  55. void mips_timer_interrupt(struct pt_regs *regs)
  56. {
  57. int irq = 7;
  58. if (r4k_offset == 0)
  59. goto null;
  60. do {
  61. kstat.irqs[0][irq]++;
  62. do_timer(regs);
  63. r4k_cur += r4k_offset;
  64. ack_r4ktimer(r4k_cur);
  65. } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
  66.          - r4k_cur) < 0x7fffffff);
  67. return;
  68. null:
  69. ack_r4ktimer(0);
  70. }
  71. /* 
  72.  * Figure out the r4k offset, the amount to increment the compare
  73.  * register for each time tick. 
  74.  * Use the Programmable Counter 1 to do this.
  75.  */
  76. unsigned long cal_r4koff(void)
  77. {
  78. unsigned long count;
  79. unsigned long cpu_pll;
  80. unsigned long cpu_speed;
  81. unsigned long start, end;
  82. unsigned long counter;
  83. int i;
  84. int trim_divide = 16;
  85. counter = inl(PC_COUNTER_CNTRL);
  86. outl(counter | PC_CNTRL_EN1, PC_COUNTER_CNTRL);
  87. while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
  88. outl(trim_divide-1, PC1_TRIM);    /* RTC now ticks at 32.768/16 kHz */
  89. while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_T1S);
  90. while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
  91. outl (0, PC1_COUNTER_WRITE);
  92. while (inl(PC_COUNTER_CNTRL) & PC_CNTRL_C1S);
  93. start = inl(PC1_COUNTER_READ);
  94. start += 2;
  95. /* wait for the beginning of a new tick */
  96. while (inl(PC1_COUNTER_READ) < start);
  97. /* Start r4k counter. */
  98. write_32bit_cp0_register(CP0_COUNT, 0);
  99. end = start + (32768 / trim_divide)/2; /* wait 0.5 seconds */
  100. while (end > inl(PC1_COUNTER_READ));
  101. count = read_32bit_cp0_register(CP0_COUNT);
  102. cpu_speed = count * 2;
  103. uart_baud_base = (((cpu_speed) / 4) / 16);
  104. return (cpu_speed / HZ);
  105. }
  106. static unsigned long __init get_mips_time(void)
  107. {
  108. return inl(PC0_COUNTER_READ);
  109. }
  110. void __init time_init(void)
  111. {
  112.         unsigned int est_freq, flags;
  113. printk("calculating r4koff... ");
  114. r4k_offset = cal_r4koff();
  115. printk("%08lx(%d)n", r4k_offset, (int) r4k_offset);
  116. //est_freq = 2*r4k_offset*HZ;
  117. est_freq = r4k_offset*HZ;
  118. est_freq += 5000;    /* round */
  119. est_freq -= est_freq%10000;
  120. printk("CPU frequency %d.%02d MHzn", est_freq/1000000, 
  121.        (est_freq%1000000)*100/1000000);
  122. r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
  123. write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
  124. set_cp0_status(ALLINTS);
  125. /* Read time from the RTC chipset. */
  126. write_lock_irqsave (&xtime_lock, flags);
  127. xtime.tv_sec = get_mips_time();
  128. xtime.tv_usec = 0;
  129. write_unlock_irqrestore(&xtime_lock, flags);
  130. }
  131. /* This is for machines which generate the exact clock. */
  132. #define USECS_PER_JIFFY (1000000/HZ)
  133. #define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff)
  134. /* Cycle counter value at the previous timer interrupt.. */
  135. static unsigned int timerhi = 0, timerlo = 0;
  136. static unsigned long
  137. div64_32(unsigned long v1, unsigned long v2, unsigned long v3)
  138. {
  139. unsigned long r0;
  140. do_div64_32(r0, v1, v2, v3);
  141. return r0;
  142. }
  143. /*
  144.  * FIXME: Does playing with the RP bit in c0_status interfere with this code?
  145.  */
  146. static unsigned long do_fast_gettimeoffset(void)
  147. {
  148. u32 count;
  149. unsigned long res, tmp;
  150. unsigned long r0;
  151. /* Last jiffy when do_fast_gettimeoffset() was called. */
  152. static unsigned long last_jiffies=0;
  153. unsigned long quotient;
  154. /*
  155.  * Cached "1/(clocks per usec)*2^32" value.
  156.  * It has to be recalculated once each jiffy.
  157.  */
  158. static unsigned long cached_quotient=0;
  159. tmp = jiffies;
  160. quotient = cached_quotient;
  161. if (tmp && last_jiffies != tmp) {
  162. last_jiffies = tmp;
  163. if (last_jiffies != 0) {
  164. r0 = div64_32(timerhi, timerlo, tmp);
  165. quotient = div64_32(USECS_PER_JIFFY, USECS_PER_JIFFY_FRAC, r0);
  166. cached_quotient = quotient;
  167. }
  168. }
  169. /* Get last timer tick in absolute kernel time */
  170. count = read_32bit_cp0_register(CP0_COUNT);
  171. /* .. relative to previous jiffy (32 bits is enough) */
  172. count -= timerlo;
  173. __asm__("multut%1,%2nt"
  174. "mfhit%0"
  175. :"=r" (res)
  176. :"r" (count),
  177.  "r" (quotient));
  178. /*
  179.    * Due to possible jiffies inconsistencies, we need to check 
  180.  * the result so that we'll get a timer that is monotonic.
  181.  */
  182. if (res >= USECS_PER_JIFFY)
  183. res = USECS_PER_JIFFY-1;
  184. return res;
  185. }
  186. void do_gettimeofday(struct timeval *tv)
  187. {
  188. unsigned int flags;
  189. read_lock_irqsave (&xtime_lock, flags);
  190. *tv = xtime;
  191. tv->tv_usec += do_fast_gettimeoffset();
  192. /*
  193.  * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
  194.  * is nonzero if the timer bottom half hasnt executed yet.
  195.  */
  196. if (jiffies - wall_jiffies)
  197. tv->tv_usec += USECS_PER_JIFFY;
  198. read_unlock_irqrestore (&xtime_lock, flags);
  199. if (tv->tv_usec >= 1000000) {
  200. tv->tv_usec -= 1000000;
  201. tv->tv_sec++;
  202. }
  203. }
  204. void do_settimeofday(struct timeval *tv)
  205. {
  206. write_lock_irq (&xtime_lock);
  207. /* This is revolting. We need to set the xtime.tv_usec correctly.
  208.  * However, the value in this location is is value at the last tick.
  209.  * Discover what correction gettimeofday would have done, and then
  210.  * undo it!
  211.  */
  212. tv->tv_usec -= do_fast_gettimeoffset();
  213. if (tv->tv_usec < 0) {
  214. tv->tv_usec += 1000000;
  215. tv->tv_sec--;
  216. }
  217. xtime = *tv;
  218. time_adjust = 0; /* stop active adjtime() */
  219. time_status |= STA_UNSYNC;
  220. time_maxerror = NTP_PHASE_LIMIT;
  221. time_esterror = NTP_PHASE_LIMIT;
  222. write_unlock_irq (&xtime_lock);
  223. }
  224. /*
  225.  * The UART baud base is not known at compile time ... if
  226.  * we want to be able to use the same code on different
  227.  * speed CPUs.
  228.  */
  229. unsigned long get_au1000_uart_baud()
  230. {
  231. return uart_baud_base;
  232. }