timer.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. * (C) Copyright 2002
  3. * Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <asm/io.h>
  25. #include <asm/i8254.h>
  26. #include <asm/ibmpc.h>
  27. static volatile unsigned long system_ticks;
  28. static int timer_init_done =0;
  29. static void timer_isr(void *unused)
  30. {
  31. system_ticks++;
  32. }
  33. unsigned long get_system_ticks(void)
  34. {
  35. return system_ticks;
  36. }
  37. #define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */
  38. #define TIMER2_VALUE 0x0a8e /* 440Hz */
  39. int timer_init(void)
  40. {
  41. system_ticks = 0;
  42. irq_install_handler(0, timer_isr, NULL);
  43. /* initialize timer 0 and 2
  44. *
  45. * Timer 0 is used to increment system_tick 1000 times/sec
  46. * Timer 1 was used for DRAM refresh in early PC's
  47. * Timer 2 is used to drive the speaker
  48. * (to stasrt a beep: write 3 to port 0x61,
  49. * to stop it again: write 0)
  50. */
  51. outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND);
  52. outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0);
  53. outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0);
  54. outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND);
  55. outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2);
  56. outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2);
  57. timer_init_done = 1;
  58. return 0;
  59. }
  60. #ifdef CFG_TIMER_GENERIC
  61. /* the unit for these is CFG_HZ */
  62. /* FixMe: implement these */
  63. void reset_timer (void)
  64. {
  65. system_ticks = 0;
  66. }
  67. ulong get_timer (ulong base)
  68. {
  69. return (system_ticks - base);
  70. }
  71. void set_timer (ulong t)
  72. {
  73. system_ticks = t;
  74. }
  75. static u16 read_pit(void)
  76. {
  77. u8 low;
  78. outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND);
  79. low = inb(PIT_BASE + PIT_T0);
  80. return ((inb(PIT_BASE + PIT_T0) << 8) | low);
  81. }
  82. /* this is not very exact */
  83. void udelay (unsigned long usec)
  84. {
  85. int counter;
  86. int wraps;
  87. if (!timer_init_done) {
  88. return;
  89. }
  90. counter = read_pit();
  91. wraps = usec/1000;
  92. usec = usec%1000;
  93. usec*=1194;
  94. usec/=1000;
  95. usec+=counter;
  96. if (usec > 1194) {
  97. usec-=1194;
  98. wraps++;
  99. }
  100. while (1) {
  101. int new_count = read_pit();
  102. if (((new_count < usec) && !wraps) || wraps < 0) {
  103. break;
  104. }
  105. if (new_count > counter) {
  106. wraps--;
  107. }
  108. counter = new_count;
  109. }
  110. }
  111. #if 0
  112. /* this is a version with debug output */
  113. void _udelay (unsigned long usec)
  114. {
  115. int counter;
  116. int wraps;
  117. int usec1, usec2, usec3;
  118. int wraps1, wraps2, wraps3, wraps4;
  119. int ctr1, ctr2, ctr3, nct1, nct2;
  120. int i;
  121. usec1=usec;
  122. if (!timer_init_done) {
  123. return;
  124. }
  125. counter = read_pit();
  126. ctr1 = counter;
  127. wraps = usec/1000;
  128. usec = usec%1000;
  129. usec2 = usec;
  130. wraps1 = wraps;
  131. usec*=1194;
  132. usec/=1000;
  133. usec+=counter;
  134. if (usec > 1194) {
  135. usec-=1194;
  136. wraps++;
  137. }
  138. usec3 = usec;
  139. wraps2 = wraps;
  140. ctr2 = wraps3 = nct1 = 4711;
  141. ctr3 = wraps4 = nct2 = 4711;
  142. i=0;
  143. while (1) {
  144. int new_count = read_pit();
  145. i++;
  146. if ((new_count < usec && !wraps) || wraps < 0) {
  147. break;
  148. }
  149. if (new_count > counter) {
  150. wraps--;
  151. }
  152. if (ctr2==4711) {
  153. ctr2 = counter;
  154. wraps3 = wraps;
  155. nct1 = new_count;
  156. } else {
  157. ctr3 = counter;
  158. wraps4 = wraps;
  159. nct2 = new_count;
  160. }
  161. counter = new_count;
  162. }
  163. printf("udelay(%d)\n", usec1);
  164. printf("counter %d\n", ctr1);
  165. printf("1: wraps %d, usec %d\n", wraps1, usec2);
  166. printf("2: wraps %d, usec %d\n", wraps2, usec3);
  167. printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3);
  168. printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4);
  169. printf("%d %d %d %d %d\n",
  170. read_pit(), read_pit(), read_pit(),
  171. read_pit(), read_pit());
  172. }
  173. #endif
  174. #endif