2 * (c) 2008-2009 Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
3 * economic rights: Technische Universität Dresden (Germany)
4 * This file is part of TUD:OS and distributed under the terms of the
5 * GNU Lesser General Public License 2.1.
6 * Please see the COPYING-LGPL-2.1 file for details.
9 #include <l4/sys/ipc.h>
10 #include <l4/sys/syscalls.h>
11 #include <l4/sys/kdebug.h>
12 #include <l4/util/port_io.h>
13 #include <l4/util/irq.h>
14 #include <l4/util/apic.h>
17 unsigned long apic_map_base = 0;
18 unsigned long apic_timer_divisor = 1;
19 unsigned long l4_scaler_apic_to_ms = 0;
22 apic_show_registers(void)
25 apic_show_register_block(unsigned int beg, unsigned int len)
30 for (i=beg; i<beg+len; i+=0x10)
33 outhex32(apic_read(i));
41 apic_show_register_block( 0x00, 0x80); // ID, Version
42 apic_show_register_block( 0x80, 0x80); // TaskPrio, Arb, ProcPrio, DFR
43 apic_show_register_block(0x100, 0x80); // ISR 0-255
44 apic_show_register_block(0x180, 0x80); // TMR 0-255
45 apic_show_register_block(0x200, 0x80); // IRR 0-255
46 apic_show_register_block(0x300, 0x80); // ICR
47 apic_show_register_block(0x380, 0x10); // Initial Count Register
51 apic_timer_set_divisor(int newdiv)
56 unsigned long tmp_value;
58 static int divisor_tab[8] =
60 APIC_TDR_DIV_1, APIC_TDR_DIV_2, APIC_TDR_DIV_4, APIC_TDR_DIV_8,
61 APIC_TDR_DIV_16, APIC_TDR_DIV_32, APIC_TDR_DIV_64, APIC_TDR_DIV_128
73 enter_kdebug("bad APIC divisor");
83 apic_timer_divisor = newdiv;
84 tmp_value = apic_read(APIC_TDCR);
87 apic_write(APIC_TDCR, tmp_value);
93 apic_check_working(void)
95 #define CLOCK_TICK_RATE 1193180 /* i8254 ticks per second */
97 unsigned long tt1, tt2;
99 unsigned int calibrate_latch = (CLOCK_TICK_RATE / 20); /* 50 ms */
104 apic_timer_disable_irq();
105 apic_timer_set_divisor(1);
106 apic_timer_write(1000000000);
108 /* Set the Gate high, disable speaker */
109 l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
111 l4util_out8(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
112 l4util_out8(calibrate_latch & 0xff, 0x42); /* LSB of count */
113 l4util_out8(calibrate_latch >> 8, 0x42); /* MSB of count */
115 tt1=apic_timer_read();
120 } while ((l4util_in8(0x61) & 0x20) == 0);
122 tt2=apic_timer_read();
123 return (tt1-tt2) != 0;
127 /* activate APIC after activating by MSR was successful *
128 * see "Intel Architecture Software Developer's Manual, *
129 * Volume 3: System Programming Guide, Appendix E" */
131 apic_activate_by_io(void)
134 unsigned long tmp_val;
137 /* mask 8259 interrupts */
138 old_21 = l4util_in8(0x21);
139 l4util_out8(0xff, 0x21);
140 old_A1 = l4util_in8(0xA1);
141 l4util_out8(0xff, 0xA1);
143 l4util_flags_save(&flags);
148 /* set LINT0 to ExtINT, edge triggered */
149 tmp_val = apic_read(APIC_LVT0);
150 tmp_val &= 0xfffe58ff;
151 tmp_val |= 0x00000700;
152 apic_write(APIC_LVT0, tmp_val);
154 /* set LINT1 to NMI, edge triggered */
155 tmp_val = apic_read(APIC_LVT1);
156 tmp_val &= 0xfffe58ff;
157 tmp_val |= 0x00000400;
158 apic_write(APIC_LVT1, tmp_val);
160 /* unmask 8259 interrupts */
161 l4util_flags_restore(&flags);
162 l4util_out8(old_A1, 0xA1);
163 l4util_out8(old_21, 0x21);
167 * Return APIC clocks per ms
170 l4_calibrate_apic (void)
172 unsigned int calibrate_latch = (CLOCK_TICK_RATE / 20); /* 50 ms */
173 unsigned int calibrate_time = 50; /* 50 ms */
178 apic_timer_disable_irq();
179 apic_timer_set_divisor(apic_timer_divisor);
180 apic_timer_write(1000000000);
182 /* Set the Gate high, disable speaker */
183 l4util_out8((l4util_in8(0x61) & ~0x02) | 0x01, 0x61);
185 l4util_out8(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
186 l4util_out8(calibrate_latch & 0xff, 0x42); /* LSB of count */
187 l4util_out8(calibrate_latch >> 8, 0x42); /* MSB of count */
191 unsigned long tt1, tt2;
192 unsigned long result;
194 tt1=apic_timer_read();
199 } while ((l4util_in8(0x61) & 0x20) == 0);
200 tt2=apic_timer_read();
202 result = (tt1-tt2)*apic_timer_divisor;
204 /* Error: ECTCNEVERSET */
208 /* Error: ECPUTOOSLOW */
209 if (result <= calibrate_time)
214 :"r" (calibrate_time),
218 l4_scaler_apic_to_ms = result;