1 /* A couple of routines to implement a low-overhead timer for drivers */ 2 3 /* 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2, or (at 7 * your option) any later version. 8 */ 9 #include "grub.h" 10 #include "osdep.h" 11 #include "io.h" 12 #include "timer.h" 13 #include "latch.h" 14 15 void __load_timer2(unsigned int ticks) 16 { 17 /* 18 * Now let's take care of PPC channel 2 19 * 20 * Set the Gate high, program PPC channel 2 for mode 0, 21 * (interrupt on terminal count mode), binary count, 22 * load 5 * LATCH count, (LSB and MSB) to begin countdown. 23 * 24 * Note some implementations have a bug where the high bits byte 25 * of channel 2 is ignored. 26 */ 27 /* Set up the timer gate, turn off the speaker */ 28 /* Set the Gate high, disable speaker */ 29 outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB); 30 /* binary, mode 0, LSB/MSB, Ch 2 */ 31 outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT); 32 /* LSB of ticks */ 33 outb(ticks & 0xFF, TIMER2_PORT); 34 /* MSB of ticks */ 35 outb(ticks >> 8, TIMER2_PORT); 36 } 37 38 static int __timer2_running(void) 39 { 40 return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0); 41 } 42 43 #if !defined(CONFIG_TSC_CURRTICKS) 44 void setup_timers(void) 45 { 46 return; 47 } 48 49 void load_timer2(unsigned int ticks) 50 { 51 return __load_timer2(ticks); 52 } 53 54 int timer2_running(void) 55 { 56 return __timer2_running(); 57 } 58 59 void ndelay(unsigned int nsecs) 60 { 61 waiton_timer2((nsecs * CLOCK_TICK_RATE)/1000000000); 62 } 63 void udelay(unsigned int usecs) 64 { 65 waiton_timer2((usecs * TICKS_PER_MS)/1000); 66 } 67 #endif /* !defined(CONFIG_TSC_CURRTICKS) */ 68 69 #if defined(CONFIG_TSC_CURRTICKS) 70 71 #define rdtsc(low,high) \ 72 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) 73 74 #define rdtscll(val) \ 75 __asm__ __volatile__ ("rdtsc" : "=A" (val)) 76 77 78 /* Number of clock ticks to time with the rtc */ 79 #define LATCH 0xFF 80 81 #define LATCHES_PER_SEC ((CLOCK_TICK_RATE + (LATCH/2))/LATCH) 82 #define TICKS_PER_LATCH ((LATCHES_PER_SEC + (TICKS_PER_SEC/2))/TICKS_PER_SEC) 83 84 static void sleep_latch(void) 85 { 86 __load_timer2(LATCH); 87 while(__timer2_running()); 88 } 89 90 /* ------ Calibrate the TSC ------- 91 * Time how long it takes to excute a loop that runs in known time. 92 * And find the convertion needed to get to CLOCK_TICK_RATE 93 */ 94 95 96 static unsigned long long calibrate_tsc(void) 97 { 98 unsigned long startlow, starthigh; 99 unsigned long endlow, endhigh; 100 101 rdtsc(startlow,starthigh); 102 sleep_latch(); 103 rdtsc(endlow,endhigh); 104 105 /* 64-bit subtract - gcc just messes up with long longs */ 106 __asm__("subl %2,%0\n\t" 107 "sbbl %3,%1" 108 :"=a" (endlow), "=d" (endhigh) 109 :"g" (startlow), "g" (starthigh), 110 "0" (endlow), "1" (endhigh)); 111 112 /* Error: ECPUTOOFAST */ 113 if (endhigh) 114 goto bad_ctc; 115 116 endlow *= TICKS_PER_LATCH; 117 return endlow; 118 119 /* 120 * The CTC wasn't reliable: we got a hit on the very first read, 121 * or the CPU was so fast/slow that the quotient wouldn't fit in 122 * 32 bits.. 123 */ 124 bad_ctc: 125 printf("bad_ctc\n"); 126 return 0; 127 } 128 129 static unsigned long clocks_per_tick; 130 void setup_timers(void) 131 { 132 if (!clocks_per_tick) { 133 clocks_per_tick = calibrate_tsc(); 134 /* Display the CPU Mhz to easily test if the calibration was bad */ 135 printf("CPU %ld Mhz\n", (clocks_per_tick/1000 * TICKS_PER_SEC)/1000); 136 } 137 } 138 139 unsigned long currticks(void) 140 { 141 unsigned long clocks_high, clocks_low; 142 unsigned long currticks; 143 /* Read the Time Stamp Counter */ 144 rdtsc(clocks_low, clocks_high); 145 146 /* currticks = clocks / clocks_per_tick; */ 147 __asm__("divl %1" 148 :"=a" (currticks) 149 :"r" (clocks_per_tick), "0" (clocks_low), "d" (clocks_high)); 150 151 152 return currticks; 153 } 154 155 static unsigned long long timer_timeout; 156 static int __timer_running(void) 157 { 158 unsigned long long now; 159 rdtscll(now); 160 return now < timer_timeout; 161 } 162 163 void udelay(unsigned int usecs) 164 { 165 unsigned long long now; 166 rdtscll(now); 167 timer_timeout = now + usecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000)); 168 while(__timer_running()); 169 } 170 void ndelay(unsigned int nsecs) 171 { 172 unsigned long long now; 173 rdtscll(now); 174 timer_timeout = now + nsecs * ((clocks_per_tick * TICKS_PER_SEC)/(1000*1000*1000)); 175 while(__timer_running()); 176 } 177 178 void load_timer2(unsigned int timer2_ticks) 179 { 180 unsigned long long now; 181 unsigned long clocks; 182 rdtscll(now); 183 clocks = timer2_ticks * ((clocks_per_tick * TICKS_PER_SEC)/CLOCK_TICK_RATE); 184 timer_timeout = now + clocks; 185 } 186 187 int timer2_running(void) 188 { 189 return __timer_running(); 190 } 191 192 #endif /* RTC_CURRTICKS */ 193