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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * indy_timer.c: Setting up the clock on the INDY 8254 controller.
  3.  *
  4.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  5.  * Copytight (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
  6.  */
  7. #include <linux/errno.h>
  8. #include <linux/init.h>
  9. #include <linux/sched.h>
  10. #include <linux/kernel.h>
  11. #include <linux/param.h>
  12. #include <linux/string.h>
  13. #include <linux/mm.h>
  14. #include <linux/interrupt.h>
  15. #include <linux/timex.h>
  16. #include <linux/kernel_stat.h>
  17. #include <asm/bootinfo.h>
  18. #include <asm/io.h>
  19. #include <asm/irq.h>
  20. #include <asm/ptrace.h>
  21. #include <asm/system.h>
  22. #include <asm/sgi/sgi.h>
  23. #include <asm/sgi/sgihpc.h>
  24. #include <asm/sgi/sgint23.h>
  25. #include <asm/sgialib.h>
  26. /* Because of a bug in the i8254 timer we need to use the onchip r4k
  27.  * counter as our system wide timer interrupt running at 100HZ.
  28.  */
  29. static unsigned long r4k_offset; /* Amount to increment compare reg each time */
  30. static unsigned long r4k_cur;    /* What counter should be at next timer irq */
  31. extern rwlock_t xtime_lock;
  32. static inline void ack_r4ktimer(unsigned long newval)
  33. {
  34. write_32bit_cp0_register(CP0_COMPARE, newval);
  35. }
  36. static int set_rtc_mmss(unsigned long nowtime)
  37. {
  38. struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS;
  39. int retval = 0;
  40. int real_seconds, real_minutes, clock_minutes;
  41. #define FROB_FROM_CLOCK(x) (((x) & 0xf) | ((((x) & 0xf0) >> 4) * 10));
  42. #define FROB_TO_CLOCK(x)  ((((((x) & 0xff) / 10)<<4) | (((x) & 0xff) % 10)) & 0xff)
  43. clock->cmd &= ~(0x80);
  44. clock_minutes = clock->min;
  45. clock->cmd |= (0x80);
  46. clock_minutes = FROB_FROM_CLOCK(clock_minutes);
  47. real_seconds = nowtime % 60;
  48. real_minutes = nowtime / 60;
  49. if(((abs(real_minutes - clock_minutes) + 15)/30) & 1)
  50. real_minutes += 30; /* correct for half hour time zone */
  51. real_minutes %= 60;
  52. if(abs(real_minutes - clock_minutes) < 30) {
  53. /* Force clock oscillator to be on. */
  54. clock->month &= ~(0x80);
  55. /* Write real_seconds and real_minutes into the Dallas. */
  56. clock->cmd &= ~(0x80);
  57. clock->sec = real_seconds;
  58. clock->min = real_minutes;
  59. clock->cmd |= (0x80);
  60. } else
  61. return -1;
  62. #undef FROB_FROM_CLOCK
  63. #undef FROB_TO_CLOCK
  64. return retval;
  65. }
  66. static long last_rtc_update;
  67. unsigned long missed_heart_beats;
  68. void indy_timer_interrupt(struct pt_regs *regs)
  69. {
  70. unsigned long count;
  71. int irq = 7;
  72. write_lock(&xtime_lock);
  73. /* Ack timer and compute new compare. */
  74. count = read_32bit_cp0_register(CP0_COUNT);
  75. /* This has races.  */
  76. if ((count - r4k_cur) >= r4k_offset) {
  77. /* If this happens to often we'll need to compensate.  */
  78. missed_heart_beats++;
  79. r4k_cur = count + r4k_offset;
  80. }
  81.         else
  82.             r4k_cur += r4k_offset;
  83. ack_r4ktimer(r4k_cur);
  84. kstat.irqs[0][irq]++;
  85. do_timer(regs);
  86. /* We update the Dallas time of day approx. every 11 minutes,
  87.  * because of how the numbers work out we need to make
  88.  * absolutely sure we do this update within 500ms before the
  89.  * next second starts, thus the following code.
  90.  */
  91. if ((time_status & STA_UNSYNC) == 0 &&
  92.     xtime.tv_sec > last_rtc_update + 660 &&
  93.     xtime.tv_usec >= 500000 - (tick >> 1) &&
  94.     xtime.tv_usec <= 500000 + (tick >> 1)) {
  95. if (set_rtc_mmss(xtime.tv_sec) == 0)
  96. last_rtc_update = xtime.tv_sec;
  97. else
  98. /* do it again in 60s  */
  99. last_rtc_update = xtime.tv_sec - 600;
  100. }
  101. write_unlock(&xtime_lock);
  102. }
  103. static unsigned long dosample(volatile unsigned char *tcwp,
  104.                               volatile unsigned char *tc2p)
  105. {
  106. unsigned long ct0, ct1;
  107. unsigned char msb, lsb;
  108. /* Start the counter. */
  109. *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MRGEN);
  110. *tc2p = (SGINT_TCSAMP_COUNTER & 0xff);
  111. *tc2p = (SGINT_TCSAMP_COUNTER >> 8);
  112. /* Get initial counter invariant */
  113. ct0 = read_32bit_cp0_register(CP0_COUNT);
  114. /* Latch and spin until top byte of counter2 is zero */
  115. do {
  116. *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT);
  117. lsb = *tc2p;
  118. msb = *tc2p;
  119. ct1 = read_32bit_cp0_register(CP0_COUNT);
  120. } while(msb);
  121. /* Stop the counter. */
  122. *tcwp = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST);
  123. /* Return the difference, this is how far the r4k counter increments
  124.  * for every one HZ.
  125.  */
  126. return ct1 - ct0;
  127. }
  128. static unsigned long __init get_indy_time(void)
  129. {
  130. struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS;
  131. unsigned int year, mon, day, hour, min, sec;
  132. /* Freeze it. */
  133. clock->cmd &= ~(0x80);
  134. /* Read regs. */
  135. sec = clock->sec;
  136. min = clock->min;
  137. hour = (clock->hr & 0x3f);
  138. day = (clock->date & 0x3f);
  139. mon = (clock->month & 0x1f);
  140. year = clock->year;
  141. /* Unfreeze clock. */
  142. clock->cmd |= 0x80;
  143. /* Frob the bits. */
  144. #define FROB1(x)  (((x) & 0xf) + ((((x) & 0xf0) >> 4) * 10));
  145. #define FROB2(x)  (((x) & 0xf) + (((((x) & 0xf0) >> 4) & 0x3) * 10));
  146. /* XXX Should really check that secs register is the same
  147.  * XXX as when we first read it and if not go back and
  148.  * XXX read the regs above again.
  149.  */
  150. sec = FROB1(sec); min = FROB1(min); day = FROB1(day);
  151. mon = FROB1(mon); year = FROB1(year);
  152. hour = FROB2(hour);
  153. #undef FROB1
  154. #undef FROB2
  155. /* Wheee... */
  156. if(year < 45)
  157. year += 30;
  158. if ((year += 1940) < 1970)
  159. year += 100;
  160. return mktime(year, mon, day, hour, min, sec);
  161. }
  162. #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
  163. void __init indy_timer_init(void)
  164. {
  165. struct sgi_ioc_timers *p;
  166. volatile unsigned char *tcwp, *tc2p;
  167. /* Figure out the r4k offset, the algorithm is very simple and works
  168.  * in _all_ cases as long as the 8254 counter register itself works ok
  169.  * (as an interrupt driving timer it does not because of bug, this is
  170.  * why we are using the onchip r4k counter/compare register to serve
  171.  * this purpose, but for r4k_offset calculation it will work ok for us).
  172.  * There are other very complicated ways of performing this calculation
  173.  * but this one works just fine so I am not going to futz around. ;-)
  174.  */
  175. p = ioc_timers;
  176. tcwp = &p->tcword;
  177. tc2p = &p->tcnt2;
  178. printk("calculating r4koff... ");
  179. dosample(tcwp, tc2p); /* First sample. */
  180. dosample(tcwp, tc2p); /* Eat one. */
  181. r4k_offset = dosample(tcwp, tc2p); /* Second sample. */
  182. printk("%08lx(%d)n", r4k_offset, (int) r4k_offset);
  183. r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
  184. write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
  185. set_cp0_status(ST0_IM, ALLINTS);
  186. sti();
  187. write_lock_irq(&xtime_lock);
  188. xtime.tv_sec = get_indy_time(); /* Read time from RTC. */
  189. xtime.tv_usec = 0;
  190. write_unlock_irq(&xtime_lock);
  191. }
  192. void indy_8254timer_irq(void)
  193. {
  194. int cpu = smp_processor_id();
  195. int irq = 4;
  196. irq_enter(cpu, irq);
  197. kstat.irqs[0][irq]++;
  198. panic("indy_8254timer_irq: Whoops, should not have gotten this IRQn");
  199. irq_exit(cpu, irq);
  200. }
  201. void do_gettimeofday(struct timeval *tv)
  202. {
  203. unsigned long flags;
  204. read_lock_irqsave(&xtime_lock, flags);
  205. *tv = xtime;
  206. read_unlock_irqrestore(&xtime_lock, flags);
  207. }
  208. void do_settimeofday(struct timeval *tv)
  209. {
  210. write_lock_irq(&xtime_lock);
  211. xtime = *tv;
  212. time_adjust = 0; /* stop active adjtime() */
  213. time_status |= STA_UNSYNC;
  214. time_maxerror = NTP_PHASE_LIMIT;
  215. time_esterror = NTP_PHASE_LIMIT;
  216. write_unlock_irq(&xtime_lock);
  217. }