Subversion Repositories shark

Rev

Rev 242 | Rev 244 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
120 giacomo 1
/* Project:     OSLib
2
 * Description: The OS Construction Kit
3
 * Date:                1.6.2000
4
 * Idea by:             Luca Abeni & Gerardo Lamastra
5
 *
6
 * OSLib is an SO project aimed at developing a common, easy-to-use
7
 * low-level infrastructure for developing OS kernels and Embedded
8
 * Applications; it partially derives from the HARTIK project but it
9
 * currently is independently developed.
10
 *
11
 * OSLib is distributed under GPL License, and some of its code has
12
 * been derived from the Linux kernel source; also some important
13
 * ideas come from studying the DJGPP go32 extender.
14
 *
15
 * We acknowledge the Linux Community, Free Software Foundation,
16
 * D.J. Delorie and all the other developers who believe in the
17
 * freedom of software and ideas.
18
 *
19
 * For legalese, check out the included GPL license.
20
 */
21
 
22
/*	Advanced Timer Managment
23
 *	Author: Giacomo Guidi <giacomo@gandalf.sssup.it>
24
 */
25
 
26
#include <ll/i386/stdlib.h>
27
#include <ll/i386/error.h>
28
#include <ll/i386/advtimer.h>
29
#include <ll/sys/ll/ll-data.h>
30
#include <ll/sys/ll/ll-func.h>
31
#include <ll/i386/pic.h>
32
#include <ll/sys/ll/event.h>
33
#include <ll/sys/ll/time.h>
34
 
130 giacomo 35
unsigned char use_tsc = 1; //Enable the TSC counter mode
120 giacomo 36
unsigned char use_cmos = 0; //Enable the RTC correction
37
 
126 giacomo 38
//Max single delta_clk_per_msec increment = clk_per_msec / MAX_DIV_INK;
39
#define MAX_DIV_INK 30000
120 giacomo 40
 
41
signed long long init_tsc;
194 giacomo 42
signed long long * ptr_init_tsc = &init_tsc;
43
 
238 giacomo 44
signed long long init_nsec; //Wraparound 292 years
194 giacomo 45
signed long long * ptr_init_nsec = &init_nsec;
46
 
120 giacomo 47
signed long long clk_per_msec;
194 giacomo 48
signed long long * ptr_clk_per_msec = &clk_per_msec;
120 giacomo 49
 
50
signed long last_delta_clk_per_msec;
51
signed long total_delta_clk_per_msec;
52
 
53
unsigned char save_CMOS_regA;
54
unsigned char save_CMOS_regB;
55
 
242 giacomo 56
//#define IRQ8_DEBUG
57
 
120 giacomo 58
void HandlerIRQ8(void *p)
59
{
60
 
61
   unsigned char set;
194 giacomo 62
 
63
   static unsigned long Mconst = 1000000;
120 giacomo 64
 
65
   static unsigned long init_step = 0;
66
 
126 giacomo 67
   signed long max_dcms = clk_per_msec / MAX_DIV_INK;
120 giacomo 68
 
194 giacomo 69
   static signed long long dn;
70
   static signed long long * ptr_dn = &dn;
120 giacomo 71
   signed long delta_clk_per_msec;
126 giacomo 72
 
120 giacomo 73
   cli();
242 giacomo 74
 
75
   #ifdef IRQ8_DEBUG
76
     message("(IRQ8");
77
   #endif
78
 
120 giacomo 79
   CMOS_READ(0x0C,set);
194 giacomo 80
 
242 giacomo 81
   __asm__("xorl %%eax,%%eax\n\t"
82
           "cpuid\n\t"
83
           "rdtsc\n\t"
194 giacomo 84
	   "pushl %%eax\n\t"
85
	   "pushl %%edx\n\t"
242 giacomo 86
           "pushl %%eax\n\t"
87
           "pushl %%edx\n\t"
88
           "xorl %%eax,%%eax\n\t"
89
           "cpuid\n\t"
90
           "popl %%edx\n\t"
91
           "popl %%eax\n\t"
194 giacomo 92
	   "subl (%%edi),%%eax\n\t"
93
	   "sbbl 4(%%edi),%%edx\n\t"
94
	   "popl 4(%%edi)\n\t"
95
	   "popl (%%edi)\n\t"
96
	   "movl %%edx,%%ecx\n\t"
97
	   "mull %4\n\t"
98
	   "pushl %%eax\n\t"
99
	   "movl %%ecx,%%eax\n\t"
100
	   "movl %%edx,%%ecx\n\t"
101
	   "mull %4\n\t"
102
	   "addl %%ecx,%%eax\n\t"
103
	   "adcl $0,%%edx\n\t"
242 giacomo 104
           "movl %7,%%ebx\n\t"
194 giacomo 105
	   "divl (%%ebx)\n\t"
106
	   "movl %%eax,4(%%esi)\n\t"
107
	   "popl %%eax\n\t"
108
	   "divl (%%ebx)\n\t"
109
	   "movl %%eax,(%%esi)\n\t"
110
 
111
	    :
242 giacomo 112
	    : "D" (ptr_init_tsc), "S" (ptr_dn), "b" (0),
113
	      "c" (0), "m" (Mconst), "a" (0), "d" (0), "m" (ptr_clk_per_msec));
120 giacomo 114
 
115
   //Offset
116
   init_nsec += dn;
194 giacomo 117
 
120 giacomo 118
   if (init_step < 5) {
119
	   init_step++;
222 giacomo 120
           sti();
242 giacomo 121
 
122
           #ifdef IRQ8_DEBUG
123
             message(")");
124
           #endif
125
 
120 giacomo 126
	   return;
127
   }
128
 
129
   dn = dn % 1000000000 - 500000000;
130
 
131
   //Delta clk/msec
132
   delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn);
133
 
134
   //clk_per_msec adjustment
135
   if (delta_clk_per_msec < 0) {
136
 
126 giacomo 137
	if (delta_clk_per_msec > -max_dcms)
120 giacomo 138
		clk_per_msec += delta_clk_per_msec;
139
	else
126 giacomo 140
		clk_per_msec -= max_dcms;
120 giacomo 141
   } else {
142
 
126 giacomo 143
	if (delta_clk_per_msec < max_dcms)
120 giacomo 144
		clk_per_msec += delta_clk_per_msec;
145
	else
126 giacomo 146
		clk_per_msec += max_dcms;
120 giacomo 147
   }
148
 
149
   last_delta_clk_per_msec = delta_clk_per_msec;
150
   total_delta_clk_per_msec += delta_clk_per_msec;
151
 
242 giacomo 152
   #ifdef IRQ8_DEBUG
153
      message(")");
154
   #endif
155
 
120 giacomo 156
   sti();
157
 
158
}
159
 
160
#ifdef CONFIG_MELAN
161
#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
162
#else
163
#  define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
164
#endif
165
 
242 giacomo 166
#define COUNTER_END 1000
120 giacomo 167
 
168
//TSC Calibration (idea from the linux kernel code)
169
void ll_calibrate_tsc(void)
170
{
171
 
172
	signed long long start;
173
	signed long long end;
243 giacomo 174
	signed long long dtsc1,dtsc2,dtsc;
120 giacomo 175
 
243 giacomo 176
	signed long start_8253, end_8253, delta1_8253, delta2_8253, delta_8253;
120 giacomo 177
 
178
	cli();
179
 
180
        /* Set the Gate high, disable speaker */
181
	outp(0x61, (inp(0x61) & ~0x02) | 0x01);
182
 
183
	outp(0x43,0xB0);			/* binary, mode 0, LSB/MSB, Ch 2 */
238 giacomo 184
	outp(0x42,0xFF);			/* LSB of count */
185
	outp(0x42,0xFF);			/* MSB of count */
242 giacomo 186
 
243 giacomo 187
        outp(0x43,0x00);
188
	start_8253 = inp(0x42);
189
	start_8253 |= inp(0x42) << 8;
242 giacomo 190
        rdtscll(start);
243 giacomo 191
 
192
	do {
193
 
194
	    outp(0x43,0x00);
195
	    end_8253 = inp(0x42);
196
	    end_8253 |= inp(0x42) << 8;
197
 
198
	} while (end_8253 > COUNTER_END);
199
 
200
        do {
201
 
202
            outp(0x43,0x00);
203
            end_8253 = inp(0x42);
204
            end_8253 |= inp(0x42) << 8;
205
 
206
        } while (end_8253 < COUNTER_END);
207
 
208
        do {
209
 
210
            outp(0x43,0x00);
211
            end_8253 = inp(0x42);
212
            end_8253 |= inp(0x42) << 8;
213
 
214
        } while (end_8253 > COUNTER_END);
215
 
216
	outp(0x43,0x00);
217
	end_8253 = inp(0x42);
218
	end_8253 |= inp(0x42) << 8;
219
        rdtscll(end);
220
 
221
	//Delta TSC
222
   	dtsc1 = end - start;
223
 
224
	//Delta PIT
225
	delta1_8253 = start_8253 - end_8253 + 0x10001;
226
 
227
 
228
        /* Set the Gate high, disable speaker */
229
	outp(0x61, (inp(0x61) & ~0x02) | 0x01);
230
 
231
	outp(0x43,0xB0);			/* binary, mode 0, LSB/MSB, Ch 2 */
232
	outp(0x42,0xFF);			/* LSB of count */
233
	outp(0x42,0xFF);			/* MSB of count */
234
 
242 giacomo 235
        outp(0x43,0x00);
120 giacomo 236
	start_8253 = inp(0x42);
243 giacomo 237
	start_8253 |= inp(0x42) << 8;
242 giacomo 238
        rdtscll(start);
239
 
120 giacomo 240
	do {
241
 
242
	    outp(0x43,0x00);
243
	    end_8253 = inp(0x42);
244
	    end_8253 |= inp(0x42) << 8;
245
 
165 giacomo 246
	} while (end_8253 > COUNTER_END);
120 giacomo 247
 
242 giacomo 248
        do {
249
 
250
            outp(0x43,0x00);
251
            end_8253 = inp(0x42);
252
            end_8253 |= inp(0x42) << 8;
253
 
254
        } while (end_8253 < COUNTER_END);
238 giacomo 255
 
242 giacomo 256
        do {
257
 
258
            outp(0x43,0x00);
259
            end_8253 = inp(0x42);
260
            end_8253 |= inp(0x42) << 8;
261
 
262
        } while (end_8253 > COUNTER_END);
238 giacomo 263
 
264
	outp(0x43,0x00);
265
	end_8253 = inp(0x42);
266
	end_8253 |= inp(0x42) << 8;
242 giacomo 267
        rdtscll(end);
238 giacomo 268
 
120 giacomo 269
	//Delta TSC
243 giacomo 270
   	dtsc2 = end - start;
120 giacomo 271
 
272
	//Delta PIT
243 giacomo 273
	delta2_8253 = start_8253 - end_8253 + 0x10001;
120 giacomo 274
 
243 giacomo 275
        if (dtsc1 > dtsc2) {
276
          dtsc = dtsc1;
277
          delta_8253 = delta1_8253;
278
        } else {
279
          dtsc = dtsc2;
280
          delta_8253 = delta2_8253;
281
        }
282
 
242 giacomo 283
	if (delta_8253 > 0x20000) {
120 giacomo 284
		message("Error calculating Delta PIT\n");
285
		ll_abort(10);
286
	}
287
 
288
	message("Delta TSC               = %10ld\n",(long)dtsc);
289
 
290
	message("Delta PIT               = %10ld\n",(long)delta_8253);
291
 
243 giacomo 292
	clk_per_msec = dtsc * CLOCK_TICK_RATE / delta_8253 / 1000;
120 giacomo 293
 
294
	message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec);
295
 
296
	sti();
297
 
298
}
299
 
300
//Low level time read function
131 giacomo 301
void ll_read_timespec(struct timespec *tspec)
120 giacomo 302
{
303
 
194 giacomo 304
    static unsigned long Gconst = 1000000000;
305
    static unsigned long Mconst = 1000000;
120 giacomo 306
 
124 giacomo 307
    if (clk_per_msec <= 0) {
308
	    NULL_TIMESPEC(tspec);
309
	    return;
310
    }
311
 
242 giacomo 312
    __asm__("xorl %%eax,%%eax\n\t"
313
            "cpuid\n\t"
314
            "rdtsc\n\t"
315
            "pushl %%eax\n\t"
316
            "pushl %%edx\n\t"
317
	    "xorl %%eax,%%eax\n\t"
318
            "cpuid\n\t"
319
            "popl %%edx\n\t"
320
            "popl %%eax\n\t"
321
            "subl (%%edi),%%eax\n\t"
194 giacomo 322
	    "sbbl 4(%%edi),%%edx\n\t"
323
	    "movl %%edx,%%ecx\n\t"
324
	    "mull %6\n\t"
325
	    "pushl %%eax\n\t"
326
	    "movl %%ecx,%%eax\n\t"
327
	    "movl %%edx,%%ecx\n\t"
328
	    "mull %6\n\t"
329
	    "addl %%ecx,%%eax\n\t"
330
	    "adcl $0,%%edx\n\t"
242 giacomo 331
            "movl %8,%%ebx\n\t"
194 giacomo 332
	    "divl (%%ebx)\n\t"
333
	    "movl %%eax,%%ecx\n\t"
334
	    "popl %%eax\n\t"
335
	    "divl (%%ebx)\n\t"
336
	    "movl %%ecx,%%edx\n\t"
337
	    "addl (%%esi),%%eax\n\t"
338
	    "adcl 4(%%esi),%%edx\n\t"
339
	    "divl %7\n\t"
340
 
341
	    : "=a" (tspec->tv_sec), "=d" (tspec->tv_nsec)
242 giacomo 342
	    : "D" (ptr_init_tsc), "S" (ptr_init_nsec), "b" (0),
343
	      "c" (0), "m" (Mconst), "m" (Gconst), "m" (ptr_clk_per_msec));
194 giacomo 344
 
120 giacomo 345
}
346
 
347
void ll_init_advtimer()
348
{
349
 
350
    if (use_tsc) {
351
 
352
	ll_calibrate_tsc();
353
 
354
	last_delta_clk_per_msec = 0;
355
	total_delta_clk_per_msec = 0;
356
 
357
	rdtscll(init_tsc); // Read start TSC
358
	init_nsec = 0;
359
 
360
	if (use_cmos) {
361
 
131 giacomo 362
	    message("CMOS adjustement enabled\n");
120 giacomo 363
 
364
    	    cli();
365
 
366
	    irq_bind(8, HandlerIRQ8, INT_FORCE);
367
 
368
	    CMOS_READ(0x0A,save_CMOS_regA);
369
	    CMOS_READ(0x0B,save_CMOS_regB);
370
 
371
	    CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
372
	    CMOS_WRITE(0x0B,0x42); // Enable Interrupt
373
 
374
	    irq_unmask(8);
375
 
376
	    sti();
377
 
378
	}
379
 
380
    } else {
381
 
382
	use_cmos = 0;
383
 
384
   }
385
 
386
}
387
 
131 giacomo 388
void ll_restore_CMOS()
120 giacomo 389
{
390
	if (use_cmos) {
391
		cli();
392
 
393
		irq_mask(8);
394
 
395
		CMOS_WRITE(0x0A,save_CMOS_regA);
396
		CMOS_WRITE(0x0B,save_CMOS_regB);
397
 
398
		sti();
399
	}
400
}