00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <arch/types.h>
00036 #include <time/clock.h>
00037 #include <time/delay.h>
00038 #include <arch/interrupt.h>
00039 #include <arch/drivers/i8259.h>
00040 #include <arch/drivers/i8254.h>
00041 #include <cpu.h>
00042 #include <config.h>
00043 #include <arch/pm.h>
00044 #include <arch/asm.h>
00045 #include <arch/cpuid.h>
00046 #include <arch.h>
00047 #include <time/delay.h>
00048 #include <interrupt.h>
00049
00050
00051
00052
00053
00054
00055 #define CLK_PORT1 0x40
00056 #define CLK_PORT4 0x43
00057
00058
00059 #define CLK_CONST 1193180
00060 #define MAGIC_NUMBER 1194
00061
00062 static void i8254_interrupt(int n, istate_t *istate);
00063
00064 void i8254_init(void)
00065 {
00066 i8254_normal_operation();
00067 }
00068
00069 void i8254_normal_operation(void)
00070 {
00071 outb(CLK_PORT4, 0x36);
00072 pic_disable_irqs(1<<IRQ_CLK);
00073 outb(CLK_PORT1, (CLK_CONST/HZ) & 0xf);
00074 outb(CLK_PORT1, (CLK_CONST/HZ) >> 8);
00075 pic_enable_irqs(1<<IRQ_CLK);
00076 exc_register(VECTOR_CLK, "i8254_clock", (iroutine) i8254_interrupt);
00077 }
00078
00079 #define LOOPS 150000
00080 #define SHIFT 11
00081 void i8254_calibrate_delay_loop(void)
00082 {
00083 __u64 clk1, clk2;
00084 __u32 t1, t2, o1, o2;
00085 __u8 not_ok;
00086
00087
00088
00089
00090
00091
00092 outb(CLK_PORT4, 0x30);
00093 outb(CLK_PORT1, 0xff);
00094 outb(CLK_PORT1, 0xff);
00095
00096 do {
00097
00098 outb(CLK_PORT4, 0xc2);
00099 not_ok = (inb(CLK_PORT1)>>6)&1;
00100 t1 = inb(CLK_PORT1);
00101 t1 |= inb(CLK_PORT1) << 8;
00102 } while (not_ok);
00103
00104 asm_delay_loop(LOOPS);
00105
00106 outb(CLK_PORT4, 0xd2);
00107 t2 = inb(CLK_PORT1);
00108 t2 |= inb(CLK_PORT1) << 8;
00109
00110
00111
00112
00113 outb(CLK_PORT4, 0xd2);
00114 o1 = inb(CLK_PORT1);
00115 o1 |= inb(CLK_PORT1) << 8;
00116
00117 asm_fake_loop(LOOPS);
00118
00119 outb(CLK_PORT4, 0xd2);
00120 o2 = inb(CLK_PORT1);
00121 o2 |= inb(CLK_PORT1) << 8;
00122
00123 CPU->delay_loop_const = ((MAGIC_NUMBER*LOOPS)/1000) / ((t1-t2)-(o1-o2)) + (((MAGIC_NUMBER*LOOPS)/1000) % ((t1-t2)-(o1-o2)) ? 1 : 0);
00124
00125 clk1 = rdtsc();
00126 delay(1<<SHIFT);
00127 clk2 = rdtsc();
00128
00129 CPU->frequency_mhz = (clk2-clk1)>>SHIFT;
00130
00131 return;
00132 }
00133
00134 void i8254_interrupt(int n, istate_t *istate)
00135 {
00136 trap_virtual_eoi();
00137 clock();
00138 }
00139