Home | History | Annotate | Download | only in core
      1 /*
      2  * arch/i386/core/i386_timer.c
      3  *
      4  * Use the "System Timer 2" to implement the udelay callback in
      5  * the BIOS timer driver. Also used to calibrate the clock rate
      6  * in the RTDSC timer driver.
      7  *
      8  * This program is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU General Public License as
     10  * published by the Free Software Foundation; either version 2, or (at
     11  * your option) any later version.
     12  */
     13 
     14 FILE_LICENCE ( GPL2_OR_LATER );
     15 
     16 #include <stddef.h>
     17 #include <gpxe/timer2.h>
     18 #include <gpxe/io.h>
     19 
     20 /* Timers tick over at this rate */
     21 #define TIMER2_TICKS_PER_SEC	1193180U
     22 
     23 /* Parallel Peripheral Controller Port B */
     24 #define	PPC_PORTB	0x61
     25 
     26 /* Meaning of the port bits */
     27 #define	PPCB_T2OUT	0x20	/* Bit 5 */
     28 #define	PPCB_SPKR	0x02	/* Bit 1 */
     29 #define	PPCB_T2GATE	0x01	/* Bit 0 */
     30 
     31 /* Ports for the 8254 timer chip */
     32 #define	TIMER2_PORT	0x42
     33 #define	TIMER_MODE_PORT	0x43
     34 
     35 /* Meaning of the mode bits */
     36 #define	TIMER0_SEL	0x00
     37 #define	TIMER1_SEL	0x40
     38 #define	TIMER2_SEL	0x80
     39 #define	READBACK_SEL	0xC0
     40 
     41 #define	LATCH_COUNT	0x00
     42 #define	LOBYTE_ACCESS	0x10
     43 #define	HIBYTE_ACCESS	0x20
     44 #define	WORD_ACCESS	0x30
     45 
     46 #define	MODE0		0x00
     47 #define	MODE1		0x02
     48 #define	MODE2		0x04
     49 #define	MODE3		0x06
     50 #define	MODE4		0x08
     51 #define	MODE5		0x0A
     52 
     53 #define	BINARY_COUNT	0x00
     54 #define	BCD_COUNT	0x01
     55 
     56 static void load_timer2 ( unsigned int ticks ) {
     57 	/*
     58 	 * Now let's take care of PPC channel 2
     59 	 *
     60 	 * Set the Gate high, program PPC channel 2 for mode 0,
     61 	 * (interrupt on terminal count mode), binary count,
     62 	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
     63 	 *
     64 	 * Note some implementations have a bug where the high bits byte
     65 	 * of channel 2 is ignored.
     66 	 */
     67 	/* Set up the timer gate, turn off the speaker */
     68 	/* Set the Gate high, disable speaker */
     69 	outb((inb(PPC_PORTB) & ~PPCB_SPKR) | PPCB_T2GATE, PPC_PORTB);
     70 	/* binary, mode 0, LSB/MSB, Ch 2 */
     71 	outb(TIMER2_SEL|WORD_ACCESS|MODE0|BINARY_COUNT, TIMER_MODE_PORT);
     72 	/* LSB of ticks */
     73 	outb(ticks & 0xFF, TIMER2_PORT);
     74 	/* MSB of ticks */
     75 	outb(ticks >> 8, TIMER2_PORT);
     76 }
     77 
     78 static int timer2_running ( void ) {
     79 	return ((inb(PPC_PORTB) & PPCB_T2OUT) == 0);
     80 }
     81 
     82 void timer2_udelay ( unsigned long usecs ) {
     83 	load_timer2 ( ( usecs * TIMER2_TICKS_PER_SEC ) / ( 1000 * 1000 ) );
     84 	while (timer2_running()) {
     85 		/* Do nothing */
     86 	}
     87 }
     88