Subversion Repositories shark

Rev

Rev 165 | Rev 222 | 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
 
120 giacomo 44
signed long long init_nsec; //Warp around 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
 
56
void HandlerIRQ8(void *p)
57
{
58
 
59
   unsigned char set;
194 giacomo 60
 
61
   static unsigned long Mconst = 1000000;
120 giacomo 62
 
63
   static unsigned long init_step = 0;
64
 
126 giacomo 65
   signed long max_dcms = clk_per_msec / MAX_DIV_INK;
120 giacomo 66
 
194 giacomo 67
   static signed long long dn;
68
   static signed long long * ptr_dn = &dn;
120 giacomo 69
   signed long delta_clk_per_msec;
126 giacomo 70
 
120 giacomo 71
   cli();
72
 
73
   CMOS_READ(0x0C,set);
194 giacomo 74
 
75
   __asm__("rdtsc\n\t"
76
	   "pushl %%eax\n\t"
77
	   "pushl %%edx\n\t"
78
	   "subl (%%edi),%%eax\n\t"
79
	   "sbbl 4(%%edi),%%edx\n\t"
80
	   "popl 4(%%edi)\n\t"
81
	   "popl (%%edi)\n\t"
82
	   "movl %%edx,%%ecx\n\t"
83
	   "mull %4\n\t"
84
	   "pushl %%eax\n\t"
85
	   "movl %%ecx,%%eax\n\t"
86
	   "movl %%edx,%%ecx\n\t"
87
	   "mull %4\n\t"
88
	   "addl %%ecx,%%eax\n\t"
89
	   "adcl $0,%%edx\n\t"
90
	   "divl (%%ebx)\n\t"
91
	   "movl %%eax,4(%%esi)\n\t"
92
	   "popl %%eax\n\t"
93
	   "divl (%%ebx)\n\t"
94
	   "movl %%eax,(%%esi)\n\t"
95
 
96
	    :
97
	    : "D" (ptr_init_tsc), "S" (ptr_dn), "b" (ptr_clk_per_msec),
98
	      "c" (0), "m" (Mconst), "a" (0), "d" (0));
120 giacomo 99
 
100
   //Offset
101
   init_nsec += dn;
194 giacomo 102
 
120 giacomo 103
   if (init_step < 5) {
104
	   init_step++;
105
	   return;
106
   }
107
 
108
   dn = dn % 1000000000 - 500000000;
109
 
110
   //Delta clk/msec
111
   delta_clk_per_msec = dn * clk_per_msec / (500000000 - dn);
112
 
113
   //clk_per_msec adjustment
114
   if (delta_clk_per_msec < 0) {
115
 
126 giacomo 116
	if (delta_clk_per_msec > -max_dcms)
120 giacomo 117
		clk_per_msec += delta_clk_per_msec;
118
	else
126 giacomo 119
		clk_per_msec -= max_dcms;
120 giacomo 120
   } else {
121
 
126 giacomo 122
	if (delta_clk_per_msec < max_dcms)
120 giacomo 123
		clk_per_msec += delta_clk_per_msec;
124
	else
126 giacomo 125
		clk_per_msec += max_dcms;
120 giacomo 126
   }
127
 
128
   last_delta_clk_per_msec = delta_clk_per_msec;
129
   total_delta_clk_per_msec += delta_clk_per_msec;
130
 
131
   sti();
132
 
133
}
134
 
135
#define HZ 100
136
 
137
#ifdef CONFIG_MELAN
138
#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
139
#else
140
#  define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
141
#endif
142
 
143
#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)
144
 
145
#define CALIBRATE_LATCH	(5 * LATCH)
146
#define CALIBRATE_TIME	(5 * 1000020/HZ)
147
 
165 giacomo 148
#define COUNTER_END 50
149
 
120 giacomo 150
//TSC Calibration (idea from the linux kernel code)
151
void ll_calibrate_tsc(void)
152
{
153
 
154
	signed long long start;
155
	signed long long end;
156
	signed long long dtsc;
157
 
158
	signed long start_8253, end_8253, delta_8253;
159
 
160
	cli();
161
 
162
        /* Set the Gate high, disable speaker */
163
	outp(0x61, (inp(0x61) & ~0x02) | 0x01);
164
 
165
	outp(0x43,0xB0);			/* binary, mode 0, LSB/MSB, Ch 2 */
166
	outp(0x42,CALIBRATE_LATCH & 0xff);	/* LSB of count */
167
	outp(0x42,CALIBRATE_LATCH >> 8);	/* MSB of count */
168
 
169
	rdtscll(start);
170
	outp(0x43,0x00);
171
	start_8253 = inp(0x42);
172
	start_8253 |= inp(0x42) << 8;
173
 
174
	do {
175
 
176
	    outp(0x43,0x00);
177
	    end_8253 = inp(0x42);
178
	    end_8253 |= inp(0x42) << 8;
179
 
165 giacomo 180
	} while (end_8253 > COUNTER_END);
120 giacomo 181
 
182
	rdtscll(end);
183
	outp(0x43,0x00);
184
	end_8253 = inp(0x42);
185
	end_8253 |= inp(0x42) << 8;
186
 
187
	//Delta TSC
188
   	dtsc = end - start;
189
 
190
	//Delta PIT
191
	delta_8253 = start_8253 - end_8253 + 1;
192
 
193
	if (delta_8253 > 0xFFFF) {
194
		message("Error calculating Delta PIT\n");
195
		ll_abort(10);
196
	}
197
 
198
	message("Delta TSC               = %10ld\n",(long)dtsc);
199
 
200
	message("Delta PIT               = %10ld\n",(long)delta_8253);
201
 
202
	clk_per_msec = dtsc * CALIBRATE_LATCH * 1000 / delta_8253 / CALIBRATE_TIME;
203
 
204
	message("Calibrated Clk_per_msec = %10ld\n",(long)clk_per_msec);
205
 
206
	sti();
207
 
208
}
209
 
210
//Low level time read function
131 giacomo 211
void ll_read_timespec(struct timespec *tspec)
120 giacomo 212
{
213
 
194 giacomo 214
    static unsigned long Gconst = 1000000000;
215
    static unsigned long Mconst = 1000000;
120 giacomo 216
 
124 giacomo 217
    if (clk_per_msec <= 0) {
218
	    NULL_TIMESPEC(tspec);
219
	    return;
220
    }
221
 
194 giacomo 222
    __asm__("rdtsc\n\t"
223
	    "subl (%%edi),%%eax\n\t"
224
	    "sbbl 4(%%edi),%%edx\n\t"
225
	    "movl %%edx,%%ecx\n\t"
226
	    "mull %6\n\t"
227
	    "pushl %%eax\n\t"
228
	    "movl %%ecx,%%eax\n\t"
229
	    "movl %%edx,%%ecx\n\t"
230
	    "mull %6\n\t"
231
	    "addl %%ecx,%%eax\n\t"
232
	    "adcl $0,%%edx\n\t"
233
	    "divl (%%ebx)\n\t"
234
	    "movl %%eax,%%ecx\n\t"
235
	    "popl %%eax\n\t"
236
	    "divl (%%ebx)\n\t"
237
	    "movl %%ecx,%%edx\n\t"
238
	    "addl (%%esi),%%eax\n\t"
239
	    "adcl 4(%%esi),%%edx\n\t"
240
	    "divl %7\n\t"
241
 
242
	    : "=a" (tspec->tv_sec), "=d" (tspec->tv_nsec)
243
	    : "D" (ptr_init_tsc), "S" (ptr_init_nsec), "b" (ptr_clk_per_msec),
244
	      "c" (0), "m" (Mconst), "m" (Gconst));
245
 
120 giacomo 246
}
247
 
248
void ll_init_advtimer()
249
{
250
 
251
    if (use_tsc) {
252
 
253
	ll_calibrate_tsc();
254
 
255
	last_delta_clk_per_msec = 0;
256
	total_delta_clk_per_msec = 0;
257
 
258
	rdtscll(init_tsc); // Read start TSC
259
	init_nsec = 0;
260
 
261
	if (use_cmos) {
262
 
131 giacomo 263
	    message("CMOS adjustement enabled\n");
120 giacomo 264
 
265
    	    cli();
266
 
267
	    irq_bind(8, HandlerIRQ8, INT_FORCE);
268
 
269
	    CMOS_READ(0x0A,save_CMOS_regA);
270
	    CMOS_READ(0x0B,save_CMOS_regB);
271
 
272
	    CMOS_WRITE(0x0A,0x2F); // Set 2 Hz Periodic Interrupt
273
	    CMOS_WRITE(0x0B,0x42); // Enable Interrupt
274
 
275
	    irq_unmask(8);
276
 
277
	    sti();
278
 
279
	}
280
 
281
    } else {
282
 
283
	use_cmos = 0;
284
 
285
   }
286
 
287
}
288
 
131 giacomo 289
void ll_restore_CMOS()
120 giacomo 290
{
291
	if (use_cmos) {
292
		cli();
293
 
294
		irq_mask(8);
295
 
296
		CMOS_WRITE(0x0A,save_CMOS_regA);
297
		CMOS_WRITE(0x0B,save_CMOS_regB);
298
 
299
		sti();
300
	}
301
}