/* * (C) Copyright 2002 * Daniel Engstr�m, Omicron Ceti AB, daniel@omicron.se. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include <common.h> #include <asm/io.h> #include <asm/i8254.h> #include <asm/ibmpc.h> static volatile unsigned long system_ticks; static int timer_init_done =0; static void timer_isr(void *unused) { system_ticks++; } unsigned long get_system_ticks(void) { return system_ticks; } #define TIMER0_VALUE 0x04aa /* 1kHz 1.9318MHz / 1000 */ #define TIMER2_VALUE 0x0a8e /* 440Hz */ int timer_init(void) { system_ticks = 0; irq_install_handler(0, timer_isr, NULL); /* initialize timer 0 and 2 * * Timer 0 is used to increment system_tick 1000 times/sec * Timer 1 was used for DRAM refresh in early PC's * Timer 2 is used to drive the speaker * (to stasrt a beep: write 3 to port 0x61, * to stop it again: write 0) */ outb(PIT_CMD_CTR0|PIT_CMD_BOTH|PIT_CMD_MODE2, PIT_BASE + PIT_COMMAND); outb(TIMER0_VALUE&0xff, PIT_BASE + PIT_T0); outb(TIMER0_VALUE>>8, PIT_BASE + PIT_T0); outb(PIT_CMD_CTR2|PIT_CMD_BOTH|PIT_CMD_MODE3, PIT_BASE + PIT_COMMAND); outb(TIMER2_VALUE&0xff, PIT_BASE + PIT_T2); outb(TIMER2_VALUE>>8, PIT_BASE + PIT_T2); timer_init_done = 1; return 0; } #ifdef CFG_TIMER_GENERIC /* the unit for these is CFG_HZ */ /* FixMe: implement these */ void reset_timer (void) { system_ticks = 0; } ulong get_timer (ulong base) { return (system_ticks - base); } void set_timer (ulong t) { system_ticks = t; } static u16 read_pit(void) { u8 low; outb(PIT_CMD_LATCH, PIT_BASE + PIT_COMMAND); low = inb(PIT_BASE + PIT_T0); return ((inb(PIT_BASE + PIT_T0) << 8) | low); } /* this is not very exact */ void udelay (unsigned long usec) { int counter; int wraps; if (!timer_init_done) { return; } counter = read_pit(); wraps = usec/1000; usec = usec%1000; usec*=1194; usec/=1000; usec+=counter; if (usec > 1194) { usec-=1194; wraps++; } while (1) { int new_count = read_pit(); if (((new_count < usec) && !wraps) || wraps < 0) { break; } if (new_count > counter) { wraps--; } counter = new_count; } } #if 0 /* this is a version with debug output */ void _udelay (unsigned long usec) { int counter; int wraps; int usec1, usec2, usec3; int wraps1, wraps2, wraps3, wraps4; int ctr1, ctr2, ctr3, nct1, nct2; int i; usec1=usec; if (!timer_init_done) { return; } counter = read_pit(); ctr1 = counter; wraps = usec/1000; usec = usec%1000; usec2 = usec; wraps1 = wraps; usec*=1194; usec/=1000; usec+=counter; if (usec > 1194) { usec-=1194; wraps++; } usec3 = usec; wraps2 = wraps; ctr2 = wraps3 = nct1 = 4711; ctr3 = wraps4 = nct2 = 4711; i=0; while (1) { int new_count = read_pit(); i++; if ((new_count < usec && !wraps) || wraps < 0) { break; } if (new_count > counter) { wraps--; } if (ctr2==4711) { ctr2 = counter; wraps3 = wraps; nct1 = new_count; } else { ctr3 = counter; wraps4 = wraps; nct2 = new_count; } counter = new_count; } printf("udelay(%d)\n", usec1); printf("counter %d\n", ctr1); printf("1: wraps %d, usec %d\n", wraps1, usec2); printf("2: wraps %d, usec %d\n", wraps2, usec3); printf("new_count[0] %d counter %d wraps %d\n", nct1, ctr2, wraps3); printf("new_count[%d] %d counter %d wraps %d\n", i, nct2, ctr3, wraps4); printf("%d %d %d %d %d\n", read_pit(), read_pit(), read_pit(), read_pit(), read_pit()); } #endif #endif