blob: a23cd6e48bf00aaa00f7785652d01bc6d518f72c [file] [log] [blame]
/*
* (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