diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2013-07-20 10:51:58 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2013-07-20 19:29:07 -0400 |
commit | c6e8c0763dee3f7c28d6ab3f2fb5c36986c288cb (patch) | |
tree | 1f70586af44e6d8cb1f644d0ae6d85d80ff891b6 /src/clock.c | |
parent | ed88f6515c18d9520efa4a41ccb70038dfbe43f9 (diff) | |
download | seabios-hppa-c6e8c0763dee3f7c28d6ab3f2fb5c36986c288cb.zip seabios-hppa-c6e8c0763dee3f7c28d6ab3f2fb5c36986c288cb.tar.gz seabios-hppa-c6e8c0763dee3f7c28d6ab3f2fb5c36986c288cb.tar.bz2 |
Move internal timer code from clock.c to a new file timer.c.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/clock.c')
-rw-r--r-- | src/clock.c | 240 |
1 files changed, 2 insertions, 238 deletions
diff --git a/src/clock.c b/src/clock.c index 2eedab8..b9a708b 100644 --- a/src/clock.c +++ b/src/clock.c @@ -10,6 +10,7 @@ #include "disk.h" // floppy_tick #include "cmos.h" // inb_cmos #include "pic.h" // pic_eoi1 +#include "pit.h" // PM_SEL_TIMER0 #include "bregs.h" // struct bregs #include "biosvar.h" // GET_GLOBAL #include "usb-hid.h" // usb_check_event @@ -26,213 +27,6 @@ #define RTC_B_DSE 0x01 -// Bits for PORT_PS2_CTRLB -#define PPCB_T2GATE (1<<0) -#define PPCB_SPKR (1<<1) -#define PPCB_T2OUT (1<<5) - -// Bits for PORT_PIT_MODE -#define PM_SEL_TIMER0 (0<<6) -#define PM_SEL_TIMER1 (1<<6) -#define PM_SEL_TIMER2 (2<<6) -#define PM_SEL_READBACK (3<<6) -#define PM_ACCESS_LATCH (0<<4) -#define PM_ACCESS_LOBYTE (1<<4) -#define PM_ACCESS_HIBYTE (2<<4) -#define PM_ACCESS_WORD (3<<4) -#define PM_MODE0 (0<<1) -#define PM_MODE1 (1<<1) -#define PM_MODE2 (2<<1) -#define PM_MODE3 (3<<1) -#define PM_MODE4 (4<<1) -#define PM_MODE5 (5<<1) -#define PM_CNT_BINARY (0<<0) -#define PM_CNT_BCD (1<<0) -#define PM_READ_COUNTER0 (1<<1) -#define PM_READ_COUNTER1 (1<<2) -#define PM_READ_COUNTER2 (1<<3) -#define PM_READ_STATUSVALUE (0<<4) -#define PM_READ_VALUE (1<<4) -#define PM_READ_STATUS (2<<4) - - -/**************************************************************** - * TSC timer - ****************************************************************/ - -#define CALIBRATE_COUNT 0x800 // Approx 1.7ms - -u32 cpu_khz VARFSEG; -u8 no_tsc VARFSEG; - -u16 pmtimer_ioport VARFSEG; -u32 pmtimer_wraps VARLOW; -u32 pmtimer_last VARLOW; - -static void -calibrate_tsc(void) -{ - u32 eax, ebx, ecx, edx, cpuid_features = 0; - - if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) { - dprintf(3, "pmtimer already configured; will not calibrate TSC\n"); - return; - } - - cpuid(0, &eax, &ebx, &ecx, &edx); - if (eax > 0) - cpuid(1, &eax, &ebx, &ecx, &cpuid_features); - - if (!(cpuid_features & CPUID_TSC)) { - SET_GLOBAL(no_tsc, 1); - SET_GLOBAL(cpu_khz, PIT_TICK_RATE / 1000); - dprintf(3, "386/486 class CPU. Using TSC emulation\n"); - return; - } - - // Setup "timer2" - u8 orig = inb(PORT_PS2_CTRLB); - outb((orig & ~PPCB_SPKR) | PPCB_T2GATE, PORT_PS2_CTRLB); - /* binary, mode 0, LSB/MSB, Ch 2 */ - outb(PM_SEL_TIMER2|PM_ACCESS_WORD|PM_MODE0|PM_CNT_BINARY, PORT_PIT_MODE); - /* LSB of ticks */ - outb(CALIBRATE_COUNT & 0xFF, PORT_PIT_COUNTER2); - /* MSB of ticks */ - outb(CALIBRATE_COUNT >> 8, PORT_PIT_COUNTER2); - - u64 start = rdtscll(); - while ((inb(PORT_PS2_CTRLB) & PPCB_T2OUT) == 0) - ; - u64 end = rdtscll(); - - // Restore PORT_PS2_CTRLB - outb(orig, PORT_PS2_CTRLB); - - // Store calibrated cpu khz. - u64 diff = end - start; - dprintf(6, "tsc calibrate start=%u end=%u diff=%u\n" - , (u32)start, (u32)end, (u32)diff); - u32 hz = diff * PIT_TICK_RATE / CALIBRATE_COUNT; - SET_GLOBAL(cpu_khz, hz / 1000); - - dprintf(1, "CPU Mhz=%u\n", hz / 1000000); -} - -/* TSC emulation timekeepers */ -u64 TSC_8254 VARLOW; -int Last_TSC_8254 VARLOW; - -static u64 -emulate_tsc(void) -{ - /* read timer 0 current count */ - u64 ret = GET_LOW(TSC_8254); - /* readback mode has slightly shifted registers, works on all - * 8254, readback PIT0 latch */ - outb(PM_SEL_READBACK | PM_READ_VALUE | PM_READ_COUNTER0, PORT_PIT_MODE); - int cnt = (inb(PORT_PIT_COUNTER0) | (inb(PORT_PIT_COUNTER0) << 8)); - int d = GET_LOW(Last_TSC_8254) - cnt; - /* Determine the ticks count from last invocation of this function */ - ret += (d > 0) ? d : (PIT_TICK_INTERVAL + d); - SET_LOW(Last_TSC_8254, cnt); - SET_LOW(TSC_8254, ret); - return ret; -} - -void pmtimer_setup(u16 ioport, u32 khz) -{ - if (!CONFIG_PMTIMER) - return; - dprintf(1, "Using pmtimer, ioport 0x%x, freq %d kHz\n", ioport, khz); - SET_GLOBAL(pmtimer_ioport, ioport); - SET_GLOBAL(cpu_khz, khz); -} - -static u64 pmtimer_get(void) -{ - u16 ioport = GET_GLOBAL(pmtimer_ioport); - u32 wraps = GET_LOW(pmtimer_wraps); - u32 pmtimer = inl(ioport) & 0xffffff; - - if (pmtimer < GET_LOW(pmtimer_last)) { - wraps++; - SET_LOW(pmtimer_wraps, wraps); - } - SET_LOW(pmtimer_last, pmtimer); - - dprintf(9, "pmtimer: %u:%u\n", wraps, pmtimer); - return (u64)wraps << 24 | pmtimer; -} - -static u64 -get_tsc(void) -{ - if (unlikely(GET_GLOBAL(no_tsc))) - return emulate_tsc(); - if (CONFIG_PMTIMER && GET_GLOBAL(pmtimer_ioport)) - return pmtimer_get(); - return rdtscll(); -} - -int -check_tsc(u64 end) -{ - return (s64)(get_tsc() - end) > 0; -} - -static void -tscdelay(u64 diff) -{ - u64 start = get_tsc(); - u64 end = start + diff; - while (!check_tsc(end)) - cpu_relax(); -} - -static void -tscsleep(u64 diff) -{ - u64 start = get_tsc(); - u64 end = start + diff; - while (!check_tsc(end)) - yield(); -} - -void ndelay(u32 count) { - tscdelay(count * GET_GLOBAL(cpu_khz) / 1000000); -} -void udelay(u32 count) { - tscdelay(count * GET_GLOBAL(cpu_khz) / 1000); -} -void mdelay(u32 count) { - tscdelay(count * GET_GLOBAL(cpu_khz)); -} - -void nsleep(u32 count) { - tscsleep(count * GET_GLOBAL(cpu_khz) / 1000000); -} -void usleep(u32 count) { - tscsleep(count * GET_GLOBAL(cpu_khz) / 1000); -} -void msleep(u32 count) { - tscsleep(count * GET_GLOBAL(cpu_khz)); -} - -// Return the TSC value that is 'msecs' time in the future. -u64 -calc_future_tsc(u32 msecs) -{ - u32 khz = GET_GLOBAL(cpu_khz); - return get_tsc() + ((u64)khz * msecs); -} -u64 -calc_future_tsc_usec(u32 usecs) -{ - u32 khz = GET_GLOBAL(cpu_khz); - return get_tsc() + ((u64)(khz/1000) * usecs); -} - - /**************************************************************** * Init ****************************************************************/ @@ -290,10 +84,9 @@ bcd2bin(u8 val) u8 Century VARLOW; void -timer_setup(void) +clock_setup(void) { dprintf(3, "init timer\n"); - calibrate_tsc(); pit_setup(); rtc_setup(); @@ -326,35 +119,6 @@ timer_setup(void) * Standard clock functions ****************************************************************/ -#define TICKS_PER_DAY (u32)((u64)60*60*24*PIT_TICK_RATE / PIT_TICK_INTERVAL) - -// Calculate the timer value at 'count' number of full timer ticks in -// the future. -u32 -calc_future_timer_ticks(u32 count) -{ - return (GET_BDA(timer_counter) + count + 1) % TICKS_PER_DAY; -} - -// Return the timer value that is 'msecs' time in the future. -u32 -calc_future_timer(u32 msecs) -{ - if (!msecs) - return GET_BDA(timer_counter); - u32 kticks = DIV_ROUND_UP((u64)msecs * PIT_TICK_RATE, PIT_TICK_INTERVAL); - u32 ticks = DIV_ROUND_UP(kticks, 1000); - return calc_future_timer_ticks(ticks); -} - -// Check if the given timer value has passed. -int -check_timer(u32 end) -{ - return (((GET_BDA(timer_counter) + TICKS_PER_DAY - end) % TICKS_PER_DAY) - < (TICKS_PER_DAY/2)); -} - // get current clock count static void handle_1a00(struct bregs *regs) |